Practical issues in specification and estimation

“In theory, there is no difference between theory and practice. But in practice, there is.”

— Benjamin Brewster

"An ounce of practice is generally worth more than a ton of theory.

— E.F. Schumacher

Theory and practice

Chapters @ref(chapter-2) and @ref(chapter-3) presented a conceptual framework (a theory of behavior) and the necessary apparatus (based on probability theory) to implement the conceptual framework. This theoretical introduction was necessary to begin work from a solid foundation, and it provides an intuitive and elegant framework to study decision-making, and a powerful one too; Daniel McFadden was awarded the Sveriges Riksbank Prize in Economic Sciences (Nobel Prize) for his contributions to random utility modelling.

Although not described in detail in previous chapters, it is worthwhile to dwell for a moment on the history of the development of the logit model as a random utility model.

In his Nobel Lecture, McFadden [-@McFadden2001economic] recounts the path that led to the development of random utility models for discrete choices. Like most important discoveries, it is a meandering path. It began early in the 20th century with a theory for economic behavior (i.e., utility) that considered heterogeneous preferences that in practice were difficult to verify empirically because of data limitations. Indeed, studies before the 1960s mostly considered aggregated demand with representative agents (i.e., archetypical consumers) to accommodate this limitation in data availability. It was only when individual-level data became more widely collected and within reach of researchers that it became possible to pay attention to the behavior of individual agents.

While economists were busy with models of aggregated demand, researchers in psychometrics and mathematical psychology, chiefly L.L Thurstone and R.D. Luce, were busy providing the technical basis for modelling what Thurstone termed Comparative Judgement (in the sense of making a decision or forming an opinion). In particular, Luce introduced the axiom of Independence of Irrelevant Alternatives (discussed in Chapter @ref(chapter-3)). According to McFadden (2001, p. 353), this axiom “simplified experimental collection of choice data by allowing multinomial choice probabilities to be inferred from binomial choice experiments.” J. Marschak was the first to introduce the work of Thurstone to econometrics in 1960, and also coined the term Random Utility Maximizing (RUM) that eventually prevailed over the comparative judgement terminology of Thurstone. McFadden’s early contributions to this body of research was developing an econometric version of Luce’s model, with strict (i.e., systematic) utilities specified as functions of the attributes of the alternatives. This allowed a research to link unobserved preference heterogeneity to a fully consistent description of the distribution of demand. Since the 1970s, discrete choice analysis has been a burgeoning area of research with a plethora of applications in economics, marketing, and travel behavior, among many other disciplines.

This brief story neatly illustrates the complex interplay between theory and practice.

Early attempts to study demand were limited due to practical considerations (i.e., the absence of data at the individual level). Once appropriate data became available, new studies continued to push the theoretical envelope. Indeed, theoretical questions have continued to inspire newer way to collect data and novel methods, and these in turn have helped us to refine our understanding of behavior. See as an example the work on decision-making in social situations [@Akerlof1997social; @Axhausen2005social; @Paez2007social] which inspired the use of new data sources [e.g., @Carrasco2007social @Axhausen2008social; @Scott2012social; @Chen2016social] as well as novel modelling approaches [e.g., @Dugundji2005discrete; @Dugundji2013social; @Kamargianni2014social] and empirical work [e.g., @vandenBerg2009social; @Goetzke2011bicycle; @Matous2017social].

Now that the preceding chapters have armed us with the theory and basic concepts to implement random utility models, it is proper that we turn our attention to the practical aspects of modelling. The best way to ensure that the concepts take hold, in my view, is to get your hands on a dataset and struggle with the practicalities of cleaning and organizing data, specifying the utility functions (a task that is more art than science), and estimating models. These skills are mostly transferable to other modelling techniques, so we will begin by applying them to the most fundamental of discrete choice models, namely the multinomial logit.

How to use this note

Remember that the source for the document you are reading is an R Notebook. Throughout the notes, you will find examples of code in segments of text called chunks. This is an example of a chunk:

print("Hats off to you, Prof. McFadden")
[1] "Hats off to you, Prof. McFadden"

If you are working with the Notebook version of the document, you can run the code by clicking the ‘play’ icon on the top right corner of the chunk. If you are reading the web-book version of the document, you will often see that the code has already been executed. You can still try it by copying and pasting into your R or RStudio console.

Learning objectives

In this practice, you will learn about:

  1. Specification of utility functions.
  2. Maximum likelihood estimation.
  3. Estimation of multinomial logit models.
  4. McFadden’s \(\rho^2\)
  5. The likelihood ratio test.

Suggested readings

  • Ben-Akiva, M. Lerman, [-@Benakiva1985discrete] Discrete Choice Analysis: Theory and Applications to Travel Demand, Chapters 4 and 5, MIT Press.
  • Hensher, D.A., Rose, J.M., Greene, W.H [-@hensher2005applied] Applied Choice Analysis: A Primer, Chapter 10, Cambridge University Press.
  • Ortuzar JD, Willumsen LG [-@Ortuzar2011modelling] Modelling Transport, Fourth Edition, Chapter 8, John Wiley and Sons.
  • Train [-@Train2009discrete] Discrete Choice Methods with Simulation, Second Edition, Chapter 3, Cambridge University Press.

Preliminaries

Load the packages used in this section:

library(tidyverse)
library(evd)
library(mlogit)
library(kableExtra)
library(plotly)

Load the dataset used in this section:

load("Commute Mac.RData")

The anatomy of utility functions

At the end Chapter @ref(chapter-3) we took, for the first time, a closer look at the systematic utilities of discrete choice models. It is useful to think about the anatomy of a typical systematic utility function. Previously, we said that some variables vary across utility functions; these are typically the attributes that describe the various alternatives (e.g., their level of service and cost). The variables that describe the decision-maker do not vary by alternative. This has implications, as seen before, for how the variables are entered into the functions. Since the model works on the basis of differences between utilities, the attributes must actually measure different levels of something or vanish.

We will describe the utilities in terms of the way different variables are introduced in the utility functions. As before, we will assume that the location parameters of the distribution are absorbed by \(J-1\) utility functions (where \(J\) is the number of alternatives) in the form of alternative specific constants.

Consider first variables that vary across alternatives. These variables can have a generic coefficient or they can have alternative-specific coefficients, as seen here:

\[ \begin{array}{l} V_{i1} =\\ V_{i2} =\\ V_{i3} =\\ \end{array} \overbrace{ \begin{array}{lll} 0 & +0 & +0\\ 0 & +\mu_2 & +0 \\ 0 & +0 & +\mu_3\\ \end{array} }^\text{alternative specific constants} \underbrace{\begin{array}{lll} +\beta_1x_{i1}\\ +\beta_1x_{i2}\\ +\beta_1x_{i3}\\ \end{array} }_{\text{alternative vars. with generic coefficients}} \overbrace{\begin{array}{lll} +\delta_1w_{i1} & +0 & +0\\ +0 & +\delta_2w_{i2} & +0\\ +0 & +0 & +\delta_3w_{i3}\\ \end{array} }^{\text{alternative vars. with specific coefficients}} \]

In many cases it is sensible to have generic coefficients. For instance, if the variable is cost, we might assume that one dollar is valued equally irrespective of the which alternative it is spent on. In other cases, the use of alternative-specific coefficients might be informative. For instance, a consistent finding in the literature is that time waiting for a bus is perceived as being more expensive than time actually on-board and traveling in the bus. Occasionally, as well, an attribute might be specific to an alternative: for instance, waiting time is often implicitly zero for travel by car and active modes of transportation (i.e., walking and cycling).

The differences of the utilities are as follows:

\[ \begin{array}{lll} V_{i2}-V_{i1}=&(\mu_2 - 0) & + &\beta_1(x_{i2} - x_{i1}) & + &(\delta_2w_{i2} - \delta_1w_{i1})\\ V_{i3}-V_{i1}=&(\mu_3 - 0) & + &\beta_1(x_{i2} - x_{i1}) & + &(\delta_3w_{i3} - \delta_1w_{i1})\\ V_{i3}-V_{i2}=&(\mu_3- \mu_2) & + &\beta_1(x_{i2} - x_{i1}) & + &(\delta_3w_{i3} - \delta_2w_{i2})\\ \end{array} \]

Variables that vary across individuals but not by alternative can be introduced with alternative-specific coefficients:

$$ \begin{array}{l} V_{i1} =\ V_{i2} =\ V_{i3} =\ \end{array}
^ _{}

^{} _ $$

Following the example above, the differences of utilities are:

\[ \begin{array}{lll} V_{i2}-V_{i1}=&(\mu_2 - 0) & + &\beta_1(x_{i2} - x_{i1}) & + &(\delta_2w_{i2} - \delta_1w_{i1}) & + &(\gamma_2 - 0)z_i\\ V_{i3}-V_{i1}=&(\mu_3 - 0) & + &\beta_1(x_{i2} - x_{i1}) & + &(\delta_3w_{i3} - \delta_1w_{i1}) & + &(\gamma_3 - 0)z_i\\ V_{i3}-V_{i2}=&(\mu_3- \mu_2) & + &\beta_1(x_{i2} - x_{i1}) & + &(\delta_3w_{i3} - \delta_2w_{i2}) & + &(\gamma_3 - \gamma_2)z_i\\ \end{array} \]

A different way of introducing individual-level variables is as part of an expansion of some coefficients, for example:

$$

\begin{array}{l} V_{i1} =\ V_{i2} =\ V_{i3} =\ \end{array}
^ _{} ^{} $$

The above expands to:

$$

\begin{array}{l} V_{i1} =\ V_{i2} =\ V_{i3} =\ \end{array}
^ _{} ^{} $$

And so the differences in utilities are:

\[ \begin{array}{lll} V_{i2}-V_{i1}=&(\mu_2 - 0) & + &\beta_{11}(x_{i2} - x_{i1}) & + &\beta_{11}(z_ix_{i2} - z_ix_{i1}) & + &(\delta_2w_{i2} - \delta_1w_{i1})\\ V_{i3}-V_{i1}=&(\mu_3 - 0) & + &\beta_{11}(x_{i2} - x_{i1}) & + &\beta_{11}(z_ix_{i3} - z_ix_{i1}) & + &(\delta_3w_{i3} - \delta_1w_{i1})\\ V_{i3}-V_{i2}=&(\mu_3- \mu_2) & + &\beta_{11}(x_{i2} - x_{i1}) & + &\beta_{11}(z_ix_{i3} - z_ix_{i2}) & + &(\delta_3w_{i3} - \delta_2w_{i2})\\ \end{array} \]

Understanding the anatomy of utility functions is essential to properly specify and estimate models.

Example: Specifying the utility functions

We will now proceed to work with a practical example, using the dataset that you encountered before in Chapter @ref(chapter-1). This dataset contains information on various modes of transportation used by people commuting to McMaster University in Canada [@Whalen2013]. The dataset was loaded above as part of the preliminaries of this chapter. We can begin by exploring the data. First, we notice that this is a dataframe that has been prepared for use with the mlogit package:

class(mc_commute)
[1] "mlogit.data" "data.frame" 

Please note that this is the same dataset that you used in Chapter @ref(chapter-1), but not the same file. For convenience, the dataset was pre-processed for use with mlogit. The contents of the dataframe can be quickly seen by means of the function head(). This function will display the first few top rows of the dataframe:

head(mc_commute, 8)

As you can see, the dataframe has been organized in a particular way. Now, instead of each row being an individual, each row is a choice situation. Since there are four alternatives in this case, each row corresponds to the choice situation for an alternative for an individual. We notice that the row names now have the format #.Alt, where # is the number of the decision maker and Alt is the name of the alternative. In this way the first four rows of the table correspond to the first decision-maker who, faced with four alternatives, chose HSR (public transportation) - as recorded in the column choice. The next four rows correspond to the second decision-maker in the sample (who also chose HSR), and so on, four rows per decision-maker. More generally, there will be \(J\) rows per decision-maker, unless not all alternatives were not available to all individuals in the sample. More on this later.

The first step towards developing a choice model is to specify the utility functions for the desired model. The package mlogit uses the package mFormula to create the functions. This package creates objects that build upon the Formula package for multi-component formulas. As seen above, utility functions can potentially have multiple components, so the functionality to build formulas in mFormula and Formula is quite useful.

Formulas for the mlogit package are defined using three parts:

\[ \text{choice} \sim \text{alternative specific vars with generic coefficients }|\text{ individual specific vars }|\text{ alternative specific vars with specific coefficients} \]

If we list all columns in the dataframe, we can see what variables are available for this analysis:

colnames(mc_commute)
 [1] "id"               "choice"           "HSR.access"       "HSR.wait"         "HSR.transfer"     "parking"          "vehind"          
 [8] "gender"           "age"              "shared"           "family"           "child"            "street_density"   "sidewalk_density"
[15] "LAT"              "LONG"             "alt"              "available"        "time"             "chid"            

Besides identifier variables id and chid, and the variable for choice, we see that several variables are specific to the individual decision-makers. These are parking (availability of a parking pass), vehind (whether the decision-maker has individual access to a private vehicle), gender, age, shared (living in shared accommodations away from the family home), family (living at the family home), and child (minors are present in the household). Furthermore, some variables relate to the physical environment of the place of residence (street_density and sidewalk_density), in addition to the coordinates of the place of residence (geocoded to the nearest major intersection or postal code centroid). One variable is alternative specific, namely time (travel time in minutes). And three variables are specific to public transportation, namely HSR.access (access time to public transportation in minutes), HSR.wait (waiting time in minutes), and HSR.transfer (number of transfers when traveling by public transportation).

We can begin by defining a very simple formula that considers only travel time. We will save this object as f1:

f1 <- mFormula(choice ~ time)

The function model.matrix allows us to see how the formula is applied to the data (we use head() to display only the top rows of the model matrix):

head(model.matrix(f1, mc_commute), 8)
        Walk:(intercept) HSR:(intercept) Car:(intercept)         time
1.Cycle                0               0               0 1.000000e+05
1.Walk                 1               0               0 6.211180e+00
1.HSR                  0               1               0 5.000000e+00
1.Car                  0               0               1 2.131439e+01
2.Cycle                0               0               0 2.000000e+00
2.Walk                 1               0               0 3.726708e+00
2.HSR                  0               1               0 1.000000e+01
2.Car                  0               0               1 1.278863e+01

We can see that the formula includes by default the alternative specific coefficients, in this case using as the mode cycling as the reference alternative. The corresponding utility functions are as follows:

\[ \begin{array}{l} V_{i\text{Cycle}} =\\ V_{i\text{Walk}} =\\ V_{i\text{HSR}} =\\ V_{i\text{HSR}} =\\ \end{array} \overbrace{ \begin{array}{lll} 0 & +0 & +0\\ \mu_{\text{Walk}} & +0 & +0\\ 0 & +\mu_{\text{HSR}} & +0 \\ 0 & +0 & +\mu_{\text{Car}}\\ \end{array} }^\text{alternative specific constants} \underbrace{\begin{array}{lll} +\beta_1\text{time}_{i\text{Cycle}}\\ +\beta_1\text{time}_{i\text{Walk}}\\ +\beta_1\text{time}_{i\text{HSR}}\\ +\beta_1\text{time}_{i\text{Car}}\\ \end{array} }_{\text{alternative vars. with generic coefficients}} \]

Define now a formula with an individual-specific variable, say age, and call it f2:

f2 <- mFormula(choice ~ time | age)

The model matrix is now:

head(model.matrix(f2, mc_commute), 8)
        Walk:(intercept) HSR:(intercept) Car:(intercept)         time Walk:age HSR:age Car:age
1.Cycle                0               0               0 1.000000e+05        0       0       0
1.Walk                 1               0               0 6.211180e+00       21       0       0
1.HSR                  0               1               0 5.000000e+00        0      21       0
1.Car                  0               0               1 2.131439e+01        0       0      21
2.Cycle                0               0               0 2.000000e+00        0       0       0
2.Walk                 1               0               0 3.726708e+00       23       0       0
2.HSR                  0               1               0 1.000000e+01        0      23       0
2.Car                  0               0               1 1.278863e+01        0       0      23

And the utility functions are therefore:

\[ \begin{array}{l} V_{i\text{Cycle}} =\\ V_{i\text{Walk}} =\\ V_{i\text{HSR}} =\\ V_{i\text{HSR}} =\\ \end{array} \overbrace{ \begin{array}{lll} 0 & +0 & +0\\ \mu_{\text{Walk}} & +0 & +0\\ 0 & +\mu_{\text{HSR}} & +0 \\ 0 & +0 & +\mu_{\text{Car}}\\ \end{array} }^\text{alternative specific constants} \underbrace{\begin{array}{lll} +\beta_1\text{time}_{i\text{Cycle}}\\ +\beta_1\text{time}_{i\text{Walk}}\\ +\beta_1\text{time}_{i\text{HSR}}\\ +\beta_1\text{time}_{i\text{Car}}\\ \end{array} }_{\text{alternative vars. with generic coefficients}} \overbrace{ \begin{array}{lll} 0 & +0 & +0\\ \gamma_{1}\text{age}_{i} & +0 & +0\\ 0 & + \gamma_{2}\text{age}_{i} & +0 \\ 0 & +0 & +\gamma_{3}\text{age}_{i}\\ \end{array} }^\text{individual vars with specific coefficients} \]

Here, we try a different formula, where time has alternative-specific instead of generic coefficients, and call it f3:

f3 <- mFormula(choice ~ 0 | age | time)

Note that, since we do not define other alternative-specific variables with generic coefficients, we have to explicitly state that there are 0 such variables!

This formula leads to the following model matrix:

head(model.matrix(f3, mc_commute), 8)
        Walk:(intercept) HSR:(intercept) Car:(intercept) Walk:age HSR:age Car:age Cycle:time Walk:time HSR:time Car:time
1.Cycle                0               0               0        0       0       0      1e+05  0.000000        0  0.00000
1.Walk                 1               0               0       21       0       0      0e+00  6.211180        0  0.00000
1.HSR                  0               1               0        0      21       0      0e+00  0.000000        5  0.00000
1.Car                  0               0               1        0       0      21      0e+00  0.000000        0 21.31439
2.Cycle                0               0               0        0       0       0      2e+00  0.000000        0  0.00000
2.Walk                 1               0               0       23       0       0      0e+00  3.726708        0  0.00000
2.HSR                  0               1               0        0      23       0      0e+00  0.000000       10  0.00000
2.Car                  0               0               1        0       0      23      0e+00  0.000000        0 12.78863

The utility functions for this are:

$$ \begin{array}{l} V_{i} =\ V_{i} =\ V_{i} =\ V_{i} =\ \end{array}
^ _ ^{}

$$

Given the utility functions, the logit probabilities for each alternative are:

\[ \begin{array}{l} P(\text{Cycle}) = \frac{e^{V_{\text{Cycle}}}}{e^{V_{\text{Cycle}}}+e^{V_{\text{Walk}}}+e^{V_{\text{HSR}}}+e^{V_{\text{Car}}}}\\ P(\text{Walk}) = \frac{e^{V_{\text{Walk}}}}{e^{V_{\text{Cycle}}}+e^{V_{\text{Walk}}}+e^{V_{\text{HSR}}}+e^{V_{\text{Car}}}}\\ P(\text{HSR}) = \frac{e^{V_{\text{Cycle}}}}{e^{V_{\text{Cycle}}}+e^{V_{\text{Walk}}}+e^{V_{\text{HSR}}}+e^{V_{\text{Car}}}}\\ P(\text{Car}) =1 - P(\text{Cycle}) - P(\text{Walk}) - P(\text{HSR})\\ \end{array} \]

The utility functions depend on the data but also on the coefficients, which we do not know a priori. Rather, these must be retrieved from the sample, as discussed next.

Estimation

Before we can calculate the choice probabilities, we need to somehow obtain coefficients for the utility functions. The process to do so is called estimation, and it involves the use of a statistical sample.

To estimate the coefficients of a model we need to define a criterion that we wish to satisfy with our choice of coefficients. Estimates can take an infinite number of values, after all, so our criterion must be optimal in some sense - in this way, once that we estimate the coefficients we can be satisfied that they are the best that we can obtain for the model under considerations, given then inputs.

A common criterion used to estimate discrete choice models is the likelihood. So what is this likelihood? Previously we encountered probability distribution functions. These functions were defined by parameters (such as the location parameter and the dispersion parameter). Given the parameters, it is possible to calculate the probability of values for a variable \(x\). A likelihood function is a similar concept, except that whereas in the probability functions the parameters were given, in a likelihood function the data are given and the parameters need to be obtained from the function.

The relevant likelihood function for the multinomial logit model is as follows: \[ L = \prod_{i=n}^N\prod_{j=1}^J P_{ij}^{y_{ij}} \] where \(P_{ij}\) is the probability of decision-maker \(i\) selecting alternative \(j\) and \(y_{ij}\) is an indicator variable that takes the value of \(1\) if individual \(i\) chose alternative \(j\) and \(0\) otherwise. The effect of the indicator variable is to turn the probabilities on and off, since \(P^0 = 1\) and \(P^1 = P\). Notice that the likelihood function is bounded between 0 and 1, but in the case of the logit model it is never exactly zero nor one, since the logit probabilities never take any of those exact values.

We can explore the behavior of the likelihood function by means of a simple example. Consider a binomial logit mode, that is, a model with only two alternatives in the choice set. The likelihood function of this model is as follows:

\[ L = \prod_{i=n}^N P_{iA}^{y_{iA}}P_{iB}^{y_{iB}} = \prod_{i=n}^N \Bigg(\frac{e^{V_{iA}}}{e^{V_{iA}} + e^{V_{iB}}}\Bigg)^{y_{iA}} \Bigg(\frac{e^{V_{iB}}}{e^{V_{iA}} + e^{V_{iB}}}\Bigg)^{y_{iB}} \]

The utility functions \(V_{iA}\) and \(V_{iB}\) depend on the data, which we know (since we have a statistical sample), and the coefficients, which we do not know.

For the example, we have the following toy sample with six individuals:

Individual Choice yiA yiB xiA xiB
1 A 1 0 5 4
2 A 1 0 2 5
3 B 0 1 5 2
4 A 1 0 1 6
5 B 0 1 4 1
6 B 0 1 3 4

Based on this sample, we can specify the utility functions in this fashion:

\[ \begin{array}{l} V_{iA} = 0 &+& \beta x_{iA}\\ V_{iB} = \mu &+& \beta x_{iB}\\ \end{array} \]

These utility functions are very similar to the first set of utility functions that we defined in the preceding section for the case of mode choice.

Next, the likelihood function for this toy sample can be writen as a function of \(\mu\) and \(\beta\). In this way, it is possible to calculate an initial value of the likelihood function bu setting \(\mu\) and \(\beta\) to zero. We will call this “Experiment 1”:

mu <- 0
beta <- 0

P1A_1 <- (exp(beta * ts$xiA[1])/(exp(beta * ts$xiA[1]) + exp(mu + beta * ts$xiB[1])))
P1B_1 <- (exp(mu + beta * ts$xiB[1])/(exp(beta * ts$xiA[1]) + exp(mu + beta * ts$xiB[1])))
P2A_1 <- (exp(beta * ts$xiA[2])/(exp(beta * ts$xiA[2]) + exp(mu + beta * ts$xiB[2])))
P2B_1 <- (exp(mu + beta * ts$xiB[2])/(exp(beta * ts$xiA[2]) + exp(mu + beta * ts$xiB[2])))
P3A_1 <- (exp(beta * ts$xiA[3])/(exp(beta * ts$xiA[3]) + exp(mu + beta * ts$xiB[3])))
P3B_1 <- (exp(mu + beta * ts$xiB[3])/(exp(beta * ts$xiA[3]) + exp(mu + beta * ts$xiB[3])))
P4A_1 <- (exp(beta * ts$xiA[4])/(exp(beta * ts$xiA[4]) + exp(mu + beta * ts$xiB[4])))
P4B_1 <- (exp(mu + beta * ts$xiB[4])/(exp(beta * ts$xiA[4]) + exp(mu + beta * ts$xiB[4])))
P5A_1 <- (exp(beta * ts$xiA[5])/(exp(beta * ts$xiA[5]) + exp(mu + beta * ts$xiB[5])))
P5B_1 <- (exp(mu + beta * ts$xiB[5])/(exp(beta * ts$xiA[5]) + exp(mu + beta * ts$xiB[5])))
P6A_1 <- (exp(beta * ts$xiA[6])/(exp(beta * ts$xiA[6]) + exp(mu + beta * ts$xiB[6])))
P6B_1 <- (exp(mu + beta * ts$xiB[6])/(exp(beta * ts$xiA[6]) + exp(mu + beta * ts$xiB[6])))
  
L <-  P1A_1^ts$yiA[1] * P1B_1^ts$yiB[1] * 
  P2A_1^ts$yiA[2] * P2B_1^ts$yiB[2] * 
  P3A_1^ts$yiA[3] * P3B_1^ts$yiB[3] * 
  P4A_1^ts$yiA[4] * P4B_1^ts$yiB[4] * 
  P5A_1^ts$yiA[5] * P5B_1^ts$yiB[5] * 
  P6A_1^ts$yiA[6] * P6B_1^ts$yiB[6] 

# Create data frame to tabulate results:
df <- data.frame(Individual = c(1, 2, 3, 4, 5, 6),
                 Choice = c("A", "A", "B", "A", "B", "B"),
                 PA = c(P1A_1, P2A_1, P3A_1, P4A_1, P5A_1, P6A_1),
                 PB = c(P1B_1, P2B_1, P3B_1, P4B_1, P5B_1, P6B_1))

kable(df, "html", digits = 4, align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  footnote(general = paste("The value of the likelihood function is ", round(L, digits = 4)))
Individual Choice PA PB
1 A 0.5 0.5
2 A 0.5 0.5
3 B 0.5 0.5
4 A 0.5 0.5
5 B 0.5 0.5
6 B 0.5 0.5
Note:
The value of the likelihood function is 0.0156

As you can see, that the logit probabilities when all coefficients are zero is \(0.5\). By setting the coefficients to zero we have defined what is called a null model. Since the variables are set to zero, this model has no useful information to estimate the probability, and therefore it assigns equal probabilities to all alternatives. The value of the likelihood function is a relatively small (positive) number (remember, the function is bounded between zero and one).

Now, we can experiment with the coefficients, by giving them different values as follows (call this “Experiment 2”):

mu <- 0.5 # -0.5
beta <- -0.5 # -0.5

P1A_2 <- (exp(beta * ts$xiA[1])/(exp(beta * ts$xiA[1]) + exp(mu + beta * ts$xiB[1])))
P1B_2 <- (exp(mu + beta * ts$xiB[1])/(exp(beta * ts$xiA[1]) + exp(mu + beta * ts$xiB[1])))
P2A_2 <- (exp(beta * ts$xiA[2])/(exp(beta * ts$xiA[2]) + exp(mu + beta * ts$xiB[2])))
P2B_2 <- (exp(mu + beta * ts$xiB[2])/(exp(beta * ts$xiA[2]) + exp(mu + beta * ts$xiB[2])))
P3A_2 <- (exp(beta * ts$xiA[3])/(exp(beta * ts$xiA[3]) + exp(mu + beta * ts$xiB[3])))
P3B_2 <- (exp(mu + beta * ts$xiB[3])/(exp(beta * ts$xiA[3]) + exp(mu + beta * ts$xiB[3])))
P4A_2 <- (exp(beta * ts$xiA[4])/(exp(beta * ts$xiA[4]) + exp(mu + beta * ts$xiB[4])))
P4B_2 <- (exp(mu + beta * ts$xiB[4])/(exp(beta * ts$xiA[4]) + exp(mu + beta * ts$xiB[4])))
P5A_2 <- (exp(beta * ts$xiA[5])/(exp(beta * ts$xiA[5]) + exp(mu + beta * ts$xiB[5])))
P5B_2 <- (exp(mu + beta * ts$xiB[5])/(exp(beta * ts$xiA[5]) + exp(mu + beta * ts$xiB[5])))
P6A_2 <- (exp(beta * ts$xiA[6])/(exp(beta * ts$xiA[6]) + exp(mu + beta * ts$xiB[6])))
P6B_2 <- (exp(mu + beta * ts$xiB[6])/(exp(beta * ts$xiA[6]) + exp(mu + beta * ts$xiB[6])))
  
L <-  P1A_2^ts$yiA[1] * P1B_2^ts$yiB[1] * 
  P2A_2^ts$yiA[2] * P2B_2^ts$yiB[2] * 
  P3A_2^ts$yiA[3] * P3B_2^ts$yiB[3] * 
  P4A_2^ts$yiA[4] * P4B_2^ts$yiB[4] * 
  P5A_2^ts$yiA[5] * P5B_2^ts$yiB[5] * 
  P6A_2^ts$yiA[6] * P6B_2^ts$yiB[6] 

# Create data frame to tabulate results:
df <- data.frame(Individual = c(1, 2, 3, 4, 5, 6),
                 Choice = c("A", "A", "B", "A", "B", "B"),
                 PA = c(P1A_2, P2A_2, P3A_2, P4A_2, P5A_2, P6A_2),
                 PB = c(P1B_2, P2B_2, P3B_2, P4B_2, P5B_2, P6B_2))

kable(df, "html", digits = 4, align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  footnote(general = paste("The value of the likelihood function is ", round(L, digits = 4)))
Individual Choice PA PB
1 A 0.2689 0.7311
2 A 0.7311 0.2689
3 B 0.1192 0.8808
4 A 0.8808 0.1192
5 B 0.1192 0.8808
6 B 0.5000 0.5000
Note:
The value of the likelihood function is 0.0672

Notice how changing the coefficients has two effects, as you would expect: the probabilities change and the value of the likelihood function changes too. Inspect the probabilities and the value of the likelihood function with the new coefficients. What do you notice?

If you are working with the R Notebook, at this point you can try changing the coefficients. Can you improve the value of the likelihood function, or maybe even make it worse?

The likelihood function can be plotted as shown below. If you hover over the plot, you can see how the value of the likelihood changes as a function of \(\mu\) and \(\beta\):

From Figure @ref(fig:fig-evi-distribution) we can see that the approximate values of the coefficients that maximize the likelihood function are \(\mu=0.10\) and \(\beta=-0.65\). If we use these coefficients to calculate the logit probabilities, we can compare to the probabilities of Experiments 1 and 2:

# Approximate values that maximize the likelihood function.
mu <- 0.10
beta <- -0.65

P1A_3 <- (exp(beta * ts$xiA[1])/(exp(beta * ts$xiA[1]) + exp(mu + beta * ts$xiB[1])))
P1B_3 <- (exp(mu + beta * ts$xiB[1])/(exp(beta * ts$xiA[1]) + exp(mu + beta * ts$xiB[1])))
P2A_3 <- (exp(beta * ts$xiA[2])/(exp(beta * ts$xiA[2]) + exp(mu + beta * ts$xiB[2])))
P2B_3 <- (exp(mu + beta * ts$xiB[2])/(exp(beta * ts$xiA[2]) + exp(mu + beta * ts$xiB[2])))
P3A_3 <- (exp(beta * ts$xiA[3])/(exp(beta * ts$xiA[3]) + exp(mu + beta * ts$xiB[3])))
P3B_3 <- (exp(mu + beta * ts$xiB[3])/(exp(beta * ts$xiA[3]) + exp(mu + beta * ts$xiB[3])))
P4A_3 <- (exp(beta * ts$xiA[4])/(exp(beta * ts$xiA[4]) + exp(mu + beta * ts$xiB[4])))
P4B_3 <- (exp(mu + beta * ts$xiB[4])/(exp(beta * ts$xiA[4]) + exp(mu + beta * ts$xiB[4])))
P5A_3 <- (exp(beta * ts$xiA[5])/(exp(beta * ts$xiA[5]) + exp(mu + beta * ts$xiB[5])))
P5B_3 <- (exp(mu + beta * ts$xiB[5])/(exp(beta * ts$xiA[5]) + exp(mu + beta * ts$xiB[5])))
P6A_3 <- (exp(beta * ts$xiA[6])/(exp(beta * ts$xiA[6]) + exp(mu + beta * ts$xiB[6])))
P6B_3 <- (exp(mu + beta * ts$xiB[6])/(exp(beta * ts$xiA[6]) + exp(mu + beta * ts$xiB[6])))
  
L <-  P1A_3^ts$yiA[1] * P1B_3^ts$yiB[1] * 
  P2A_3^ts$yiA[2] * P2B_3^ts$yiB[2] * 
  P3A_3^ts$yiA[3] * P3B_3^ts$yiB[3] * 
  P4A_3^ts$yiA[4] * P4B_3^ts$yiB[4] * 
  P5A_3^ts$yiA[5] * P5B_3^ts$yiB[5] * 
  P6A_3^ts$yiA[6] * P6B_3^ts$yiB[6] 

# Create data frame to tabulate results:
df <- data.frame(Individual = c(1, 2, 3, 4, 5, 6),
                 Choice = c("A", "A", "B", "A", "B", "B"),
                 PA_1 = c(P1A_1, P2A_1, P3A_1, P4A_1, P5A_1, P6A_1),
                 PB_1 = c(P1B_1, P2B_1, P3B_1, P4B_1, P5B_1, P6B_1),
                 PA_1 = c(P1A_2, P2A_2, P3A_2, P4A_2, P5A_2, P6A_2),
                 PB_1 = c(P1B_2, P2B_2, P3B_2, P4B_2, P5B_2, P6B_2),
                 PA_1 = c(P1A_3, P2A_3, P3A_3, P4A_3, P5A_3, P6A_3),
                 PB_1 = c(P1B_3, P2B_3, P3B_3, P4B_3, P5B_3, P6B_3))

kable(df, "html", digits = 4, 
      col.names = c("Individual", "Choice", "PA", "PB", "PA", "PB", "PA", "PB"),
      align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  add_header_above(c(" " = 1, " " = 1, "Experiment 1" = 2, "Experiment 2" = 2, "Approx Max Likelihood" = 2))
Experiment 1
Experiment 2
Approx Max Likelihood
Individual Choice PA PB PA PB PA PB
1 A 0.5 0.5 0.1192 0.8808 0.3208 0.6792
2 A 0.5 0.5 0.9820 0.0180 0.8641 0.1359
3 B 0.5 0.5 0.0067 0.9933 0.1141 0.8859
4 A 0.5 0.5 0.9991 0.0009 0.9589 0.0411
5 B 0.5 0.5 0.0067 0.9933 0.1141 0.8859
6 B 0.5 0.5 0.7311 0.2689 0.6341 0.3659

Maximizing the likelihood is a useful criterion to estimate the coefficients of the models, since this criterion provides the optimal probabilities of the right alternative being chosen. Mind you, this does not necessarily mean that those probabilities will be high - however, we can be certain that they will be the best for the model under consideration for the sample given.

In this toy example we “solved” the problem of maximizing the likelihood by hand. This is rather difficult, unfeasible even, in most applied situations with large samples and/or more than one variable. Fortunately, there are a number of numerical algorithms that can be used to maximize the likelihood. We will not discuss this in detail, but interested readers can consult Train [@Train2009discrete; Section 3.7] for details. The mlogit package imports the package maxLik [@Henningsen2011maxlik], which implements canonical algorithms including Newton-Raphson, the Berndt–Hall–Hall–Hausman (or BHHH), and the Broyden–Fletcher–Goldfarb–Shanno (or BFGS) algorithm.

In practice, the algorithms above maximize not the likelihood function, but a transformation thereof, called the log-likelihood, which is obtained by taking the natural logarithm of the function, to give: \[ l = \sum_{i=n}^N\sum_{j=1}^J y_{ij}log(P_{ij}) \] Since the likelihood function is bound between zero and one, the log-likelihood is bound between minus infinity and zero. The value of the maximized log-likelihood function provides a useful diagnostic to compare models, since higher values are indicative of a better model. Several statistical tests (such as the likelihood ratio) can be used to test the hypothesis that a model is a significant improvement over other, and are thus useful for model selection purposes. However, before discussing model diagnostics, we will see how multinomial logit models are estimated using mlogit.

Example: A logit model of mode choice

Coming back to the transportation mode choice dataset, we had already defined some formulas (i.e., utility functions) that we can use to estimate a model.

The function to estimate a model is mlogit(). This function requires at least two arguments: an mFormula object and a dataset. We can verify that the formulas we created above are of this class:

class(f1)
[1] "mFormula" "Formula"  "formula" 
class(f2)
[1] "mFormula" "Formula"  "formula" 
class(f3)
[1] "mFormula" "Formula"  "formula" 

The value (output) of the function can be named and saved to an object for further analysis or for further processing, post-estimation. Begin by estimating a model using the simplest of our formulas:

model1 <- mlogit(f1, mc_commute)
summary(model1)

Call:
mlogit(formula = choice ~ time, data = mc_commute, method = "nr")

Frequencies of alternatives:
   Cycle     Walk      HSR      Car 
0.034884 0.516715 0.244186 0.204215 

nr method
6 iterations, 0h:0m:0s 
g'(-H)^-1g = 4.14E-05 
successive function values within tolerance limits 

Coefficients :
                    Estimate  Std. Error z-value  Pr(>|z|)    
Walk:(intercept)  2.8006e+00  1.5419e-01 18.1632 < 2.2e-16 ***
HSR:(intercept)   1.7270e+00  1.5493e-01 11.1471 < 2.2e-16 ***
Car:(intercept)   1.8978e+00  1.6151e-01 11.7506 < 2.2e-16 ***
time             -9.2134e-06  1.0585e-06 -8.7037 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Log-Likelihood: -1509.6
McFadden R^2:  0.026441 
Likelihood ratio test : chisq = 82 (p.value = < 2.22e-16)

The output of the function includes the estimated frequencies of alternatives in addition to information about the optimization procedure. For instance, the message “successive function values within tolerance limits” indicates that the algorithm converged normally.

The output also reports the estimated values of the coefficients, along with standard errors, z-values, and p-values. The null hypothesis associated with the coefficients is that they are zero. An analyst can reject the null hypothesis in any case, but small p-values indicate a low probability that the coefficient is zero - and therefore increase the confidence that by rejecting the null the analyst is not mistakenly rejecting a true zero. In the present case, with p-values smaller than 0.0001, the null hypothesis can be comfortably rejected for every coefficient. The small p-values mean that it is highly unlikely that the coefficients are zero.

This simple model includes three alternative-specific constants and one alternative-specific variable with a generic coefficient. The signs of the coefficients are informative. Since the reference mode is “Cycle”, the positive values of the constants indicate that, other things being equal, cycling is the least preferred mode, followed by HSR and then Car. The most preferred mode (again, other things being equal), is Walk. This is verified from the estimated frequencies of the modes.

The negative coefficient for time indicates that time is a “cost”, in other words, the utility of travelling tends to decline with increasing travel times. This indicates that slower modes will tend to have lower utilities.

Finally, the maximized value of the log-likelihood function is reported, along with two diagnostics, McFadden R^2 (in reality \(\rho^2\)) and a likelihood ratio test. We will come back to these diagnostics below, but first, we will estimate a new model using the second formula.

model2 <- mlogit(f2, mc_commute)
summary(model2)

Call:
mlogit(formula = choice ~ time | age, data = mc_commute, method = "nr")

Frequencies of alternatives:
   Cycle     Walk      HSR      Car 
0.034884 0.516715 0.244186 0.204215 

nr method
6 iterations, 0h:0m:0s 
g'(-H)^-1g = 4.3E-05 
successive function values within tolerance limits 

Coefficients :
                    Estimate  Std. Error z-value  Pr(>|z|)    
Walk:(intercept)  4.7672e+00  6.9102e-01  6.8988 5.245e-12 ***
HSR:(intercept)   1.9714e+00  6.5141e-01  3.0263  0.002476 ** 
Car:(intercept)   1.0572e+00  6.4186e-01  1.6471  0.099543 .  
time             -9.0888e-06  1.0778e-06 -8.4326 < 2.2e-16 ***
Walk:age         -9.0142e-02  2.9816e-02 -3.0233  0.002501 ** 
HSR:age          -1.0414e-02  2.7417e-02 -0.3798  0.704064    
Car:age           3.7357e-02  2.6923e-02  1.3876  0.165271    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Log-Likelihood: -1480.4
McFadden R^2:  0.045309 
Likelihood ratio test : chisq = 140.51 (p.value = < 2.22e-16)

Now there is an individual-specific variable in the model (i.e., age). Only one of those coefficients is significant at conventional levels (i.e., \(p<0.05\)), and it is negative. Since the reference is “Cycle”, a negative value indicates that the utility of walking declines with age with respect to the utility of cycling. Two other coefficients for age (in the utility of HSR and CAR) are not significantly different from zero, meaning that age does not significantly change the utility of travel by HSR and Car with respect to Cycle.

Note that it is possible to select the reference level for the utilities when estimating the model. For example, lets reestimate the model above, but now using the utility of Walk as the reference:

model2 <- mlogit(f2, mc_commute, reflevel = "Walk")
summary(model2)

Call:
mlogit(formula = choice ~ time | age, data = mc_commute, reflevel = "Walk", 
    method = "nr")

Frequencies of alternatives:
    Walk    Cycle      HSR      Car 
0.516715 0.034884 0.244186 0.204215 

nr method
6 iterations, 0h:0m:0s 
g'(-H)^-1g = 4.3E-05 
successive function values within tolerance limits 

Coefficients :
                     Estimate  Std. Error z-value  Pr(>|z|)    
Cycle:(intercept) -4.7672e+00  6.9102e-01 -6.8988 5.245e-12 ***
HSR:(intercept)   -2.7959e+00  4.1947e-01 -6.6652 2.644e-11 ***
Car:(intercept)   -3.7100e+00  4.1768e-01 -8.8825 < 2.2e-16 ***
time              -9.0888e-06  1.0778e-06 -8.4326 < 2.2e-16 ***
Cycle:age          9.0142e-02  2.9816e-02  3.0233  0.002501 ** 
HSR:age            7.9728e-02  1.9135e-02  4.1666 3.091e-05 ***
Car:age            1.2750e-01  1.8769e-02  6.7931 1.098e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Log-Likelihood: -1480.4
McFadden R^2:  0.045309 
Likelihood ratio test : chisq = 140.51 (p.value = < 2.22e-16)

Now all age-related coefficients are significant! Whereas some of them are not significantly different with respect to each other as seen above (e.g. Cycle and HSR), the are all significantly different from the reference. Since the coefficients are positive, this indicates that the utilities of cycling, using HSR, and traveling by car all increase with age with respect to walking.

The value of the maximized log-likelihood and other diagnostics are identical, irrespective of which mode is selected as a utility. In essence, the models are the same, but they provide a different perspective on how some coefficients relate to each other across alternatives.

We can visually explore how the probability of choosing different modes varies with age. First summarize the age variable:

summary(mc_commute$age)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  17.00   20.00   21.00   22.08   23.00   60.00 

Copy the dataframe used to estimate the model, but only enough columns to explore an age range of 10 years, say from 17 to 26. Since there are four alternatives, this means that we need fourty rows (\(J = 4\) and ten one-year intervals):

mc_commute_predict <- mc_commute[1:40,]

Replace the age variable using values for ages 17 to 26:

mc_commute_predict$age <- rep(c(17:26), each = 4)

Replace time by median travel time:

mc_commute_predict$time <- median(mc_commute$time)

Next, predict the probabilities using the predict() function:

probs <- predict(model2, newdata = mc_commute_predict)

The value (output) of predict is a 10-by-4 matrix that contains the probability for ten age values (i.e., 16, 17, 18, …, 26), and four modes (Walk, Cycle, HSR, Car). To facilitate plotting, we add the age values and then reshape that 10-by-4 matrix as follows:

probs <- data.frame(age = c(17:26), probs) %>% gather(key = "Mode", value = "Probability", -age)

By “gathering” the probabilities, now the data frame has one column with the mode and one column with the probability. We can then plot, using a different colors for each alternative:

ggplot(data = probs, aes(x = age, y = Probability, color = Mode)) +
  geom_line()

We can see that the probability of walking (for a trip that takes the median duration in the sample) declines with age. The probability of using the three other modes increases with age, but more rapidly for car than for transit or cycling.

Comparing models: McFadden’s \(\rho^2\)

The log-likelihood reported in the summary of the model is useful as a measure of goodness of fit. Recall that the likelihood of this model is bounded between \(0\) and \(1\), and therefore the log-likelihood is bounded at the upper end by \(0\) (it is minus infinity at the lower end). We also know that higher values of the likelihood represent better fits.

One simple diagnostic to compare the fit of models is McFadden’s \(\rho^2\). This summary diagnostic is defined as follows: \[ \rho^2 = 1 - \frac{l^*}{l_0} \] where \(l^*\) is the value of the maximized log-likelihood and \(l_0\) is the value of the log-likelihood of a null model (perhaps without constants, or a constants only model). If the model is uninformative, its log-likelihood will tend to the likelihood of the null model. In this case \(l^*/l_0\) tends to one and therefore \(\rho^2\) tends to zero. If the maximized log-likelihood of the model tends to 0 (the upper limit for the log-likelihood function), \(\rho^2\) tends to one.

Although \(\rho^2\) is bounded between zero and one, just like the coefficient of determination \(R^2\) in regression analysis, its interpretation is not the same as for \(R^2\). Whereas \(R^2\) is interpreted as the proportion of variance explained by the model, \(\rho^2\) lacks such an interpretation. Also, the values of \(\rho^2\) tend to be lower, and values of \(0.4\) are conventionally considered very good fits. The main utility of McFadden’s \(\rho^2\) is as a quick way of comparing the relative fit of different models, rather than assessing the fit against an absolute value of goodness of fit.

Comparing models: the likelihood ratio test

Another way to compare models is by means of the likelihood ratio test. This test compares the log-likelihood of two models to assess whether they are significantly different. The test follows the \(\chi^2\) distribution with degrees of freedom equal to the difference in the number of coefficients between the two models. The test requires a base model and a full model, and the base model must nest within the full model. Nesting in this sense means that full model must be reducible to the base model by setting some coefficients to zero.

For example, consider the utility functions of model2: \[ \begin{array}{l} V_{i\text{Cycle}} = 0 &+& \beta_1\text{time}_{i\text{Cycle}} &+& 0\\ V_{i\text{Walk}} = \mu_{\text{Walk}} &+& \beta_1\text{time}_{i\text{Walk}} &+& \gamma_{1}\text{age}_{i}\\ V_{i\text{HSR}} = \mu_{\text{HSR}} &+& \beta_1\text{time}_{i\text{HSR}} &+& \gamma_{2}\text{age}_{i}\\ V_{i\text{HSR}} = \mu_{\text{Car}} &+& \beta_1\text{time}_{i\text{Car}} &+& \gamma_{3}\text{age}_{i}\\ \end{array} \]

We can reduce this model to model1 by setting \(\gamma_{1}=\gamma_{2}=\gamma_{3}=0\): \[ \begin{array}{l} V_{i\text{Cycle}} = 0 &+& \beta_1\text{time}_{i\text{Cycle}}\\ V_{i\text{Walk}} = \mu_{\text{Walk}} &+& \beta_1\text{time}_{i\text{Walk}}\\ V_{i\text{HSR}} = \mu_{\text{HSR}} &+& \beta_1\text{time}_{i\text{HSR}}\\ V_{i\text{HSR}} = \mu_{\text{Car}} &+& \beta_1\text{time}_{i\text{Car}}\\ \end{array} \]

In this way, model1 “nests” in model2.

In the summary of the models, the likelihood ratio test is reported. See:

summary(model1)

Call:
mlogit(formula = choice ~ time, data = mc_commute, method = "nr")

Frequencies of alternatives:
   Cycle     Walk      HSR      Car 
0.034884 0.516715 0.244186 0.204215 

nr method
6 iterations, 0h:0m:0s 
g'(-H)^-1g = 4.14E-05 
successive function values within tolerance limits 

Coefficients :
                    Estimate  Std. Error z-value  Pr(>|z|)    
Walk:(intercept)  2.8006e+00  1.5419e-01 18.1632 < 2.2e-16 ***
HSR:(intercept)   1.7270e+00  1.5493e-01 11.1471 < 2.2e-16 ***
Car:(intercept)   1.8978e+00  1.6151e-01 11.7506 < 2.2e-16 ***
time             -9.2134e-06  1.0585e-06 -8.7037 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Log-Likelihood: -1509.6
McFadden R^2:  0.026441 
Likelihood ratio test : chisq = 82 (p.value = < 2.22e-16)

The test reported in the output of the model is against the null model, that is, a model with no variables at all. This is the least informative of all models.

When two non-null models need to be compared, the lrtest function implements the likelihood ratio test for two inputs, which are two mlogit models, as follows:

lrtest(model1, model2)
Likelihood ratio test

Model 1: choice ~ time
Model 2: choice ~ time | age
  #Df  LogLik Df  Chisq Pr(>Chisq)    
1   4 -1509.6                         
2   7 -1480.4  3 58.512  1.222e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Notice that the number of degrees of freedom (Df) is \(3\): this is because there are three individual-specific parameters in model2 that are not present in model1. The null hypothesis of the test is that the log-likelihood of the two models is not different, in other words, that the alternate model is not an improvement over the base model.

In the present case, the very small \(p\)-value leads us to reject the null hypothesis, and the conclusion is that model2, which includes age, is a significant improvement over model1, which does not.

Exercise

  1. In the example in this chapter we estimated the probabilities of choosing different modes by age setting travel time to the in-sample median. Use model2 to calculate the probability of choosing the modes but now as a function of travel time, for ages 17, 20, 23, and 26.

  2. Estimate a model using formula f3 (call it model3). Discuss the output of this model.

  3. Use the likelihood ratio test to compare model3 to model1.

  4. Can you use the likelihood ratio test to compare model3 to model2? Discuss.

LS0tDQp0aXRsZTogIjA0IFByYWN0aWNhbCBNYXR0ZXJzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBQcmFjdGljYWwgaXNzdWVzIGluIHNwZWNpZmljYXRpb24gYW5kIGVzdGltYXRpb24geyNjaGFwdGVyLTR9DQoNCj4gICJJbiB0aGVvcnksIHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGVvcnkgYW5kIHByYWN0aWNlLiBCdXQgaW4gcHJhY3RpY2UsIHRoZXJlIGlzLiINCj4NCj4gLS0tIEJlbmphbWluIEJyZXdzdGVyDQoNCg0KPiAiQW4gb3VuY2Ugb2YgcHJhY3RpY2UgaXMgZ2VuZXJhbGx5IHdvcnRoIG1vcmUgdGhhbiBhIHRvbiBvZiB0aGVvcnkuDQo+DQo+IC0tLSBFLkYuIFNjaHVtYWNoZXINCg0KIyMgVGhlb3J5IGFuZCBwcmFjdGljZQ0KDQpDaGFwdGVycyBcQHJlZihjaGFwdGVyLTIpIGFuZCBcQHJlZihjaGFwdGVyLTMpIHByZXNlbnRlZCBhIGNvbmNlcHR1YWwgZnJhbWV3b3JrIChhIHRoZW9yeSBvZiBiZWhhdmlvcikgYW5kIHRoZSBuZWNlc3NhcnkgYXBwYXJhdHVzIChiYXNlZCBvbiBwcm9iYWJpbGl0eSB0aGVvcnkpIHRvIGltcGxlbWVudCB0aGUgY29uY2VwdHVhbCBmcmFtZXdvcmsuIFRoaXMgdGhlb3JldGljYWwgaW50cm9kdWN0aW9uIHdhcyBuZWNlc3NhcnkgdG8gYmVnaW4gd29yayBmcm9tIGEgc29saWQgZm91bmRhdGlvbiwgYW5kIGl0IHByb3ZpZGVzIGFuIGludHVpdGl2ZSBhbmQgZWxlZ2FudCBmcmFtZXdvcmsgdG8gc3R1ZHkgZGVjaXNpb24tbWFraW5nLCBhbmQgYSBwb3dlcmZ1bCBvbmUgdG9vOyBEYW5pZWwgTWNGYWRkZW4gd2FzIGF3YXJkZWQgdGhlIFN2ZXJpZ2VzIFJpa3NiYW5rIFByaXplIGluIEVjb25vbWljIFNjaWVuY2VzIChbTm9iZWwgUHJpemVdKGh0dHBzOi8vd3d3Lm5vYmVscHJpemUub3JnL3ByaXplcy9lY29ub21pYy1zY2llbmNlcy8yMDAwL21jZmFkZGVuL2RpcGxvbWEvKSkgZm9yIGhpcyBjb250cmlidXRpb25zIHRvIHJhbmRvbSB1dGlsaXR5IG1vZGVsbGluZy4NCg0KQWx0aG91Z2ggbm90IGRlc2NyaWJlZCBpbiBkZXRhaWwgaW4gcHJldmlvdXMgY2hhcHRlcnMsIGl0IGlzIHdvcnRod2hpbGUgdG8gZHdlbGwgZm9yIGEgbW9tZW50IG9uIHRoZSBoaXN0b3J5IG9mIHRoZSBkZXZlbG9wbWVudCBvZiB0aGUgbG9naXQgbW9kZWwgYXMgYSByYW5kb20gdXRpbGl0eSBtb2RlbC4NCg0KSW4gaGlzIE5vYmVsIExlY3R1cmUsIFtNY0ZhZGRlbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRGFuaWVsX01jRmFkZGVuKSBbLUBNY0ZhZGRlbjIwMDFlY29ub21pY10gcmVjb3VudHMgdGhlIHBhdGggdGhhdCBsZWQgdG8gdGhlIGRldmVsb3BtZW50IG9mIHJhbmRvbSB1dGlsaXR5IG1vZGVscyBmb3IgZGlzY3JldGUgY2hvaWNlcy4gTGlrZSBtb3N0IGltcG9ydGFudCBkaXNjb3ZlcmllcywgaXQgaXMgYSBtZWFuZGVyaW5nIHBhdGguIEl0IGJlZ2FuIGVhcmx5IGluIHRoZSAyMHRoIGNlbnR1cnkgd2l0aCBhIHRoZW9yeSBmb3IgZWNvbm9taWMgYmVoYXZpb3IgKGkuZS4sIHV0aWxpdHkpIHRoYXQgY29uc2lkZXJlZCBoZXRlcm9nZW5lb3VzIHByZWZlcmVuY2VzIHRoYXQgaW4gcHJhY3RpY2Ugd2VyZSBkaWZmaWN1bHQgdG8gdmVyaWZ5IGVtcGlyaWNhbGx5IGJlY2F1c2Ugb2YgZGF0YSBsaW1pdGF0aW9ucy4gSW5kZWVkLCBzdHVkaWVzIGJlZm9yZSB0aGUgMTk2MHMgbW9zdGx5IGNvbnNpZGVyZWQgYWdncmVnYXRlZCBkZW1hbmQgd2l0aCByZXByZXNlbnRhdGl2ZSBhZ2VudHMgKGkuZS4sIGFyY2hldHlwaWNhbCBjb25zdW1lcnMpIHRvIGFjY29tbW9kYXRlIHRoaXMgbGltaXRhdGlvbiBpbiBkYXRhIGF2YWlsYWJpbGl0eS4gSXQgd2FzIG9ubHkgd2hlbiBpbmRpdmlkdWFsLWxldmVsIGRhdGEgYmVjYW1lIG1vcmUgd2lkZWx5IGNvbGxlY3RlZCBhbmQgd2l0aGluIHJlYWNoIG9mIHJlc2VhcmNoZXJzIHRoYXQgaXQgYmVjYW1lIHBvc3NpYmxlIHRvIHBheSBhdHRlbnRpb24gdG8gdGhlIGJlaGF2aW9yIG9mIGluZGl2aWR1YWwgYWdlbnRzLiANCg0KV2hpbGUgZWNvbm9taXN0cyB3ZXJlIGJ1c3kgd2l0aCBtb2RlbHMgb2YgYWdncmVnYXRlZCBkZW1hbmQsIHJlc2VhcmNoZXJzIGluIHBzeWNob21ldHJpY3MgYW5kIG1hdGhlbWF0aWNhbCBwc3ljaG9sb2d5LCBjaGllZmx5IFtMLkwgVGh1cnN0b25lXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb3Vpc19MZW9uX1RodXJzdG9uZSkgYW5kIFtSLkQuIEx1Y2VdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1IuX0R1bmNhbl9MdWNlKSwgd2VyZSBidXN5IHByb3ZpZGluZyB0aGUgdGVjaG5pY2FsIGJhc2lzIGZvciBtb2RlbGxpbmcgd2hhdCBUaHVyc3RvbmUgdGVybWVkIF9Db21wYXJhdGl2ZSBKdWRnZW1lbnRfIChpbiB0aGUgc2Vuc2Ugb2YgbWFraW5nIGEgZGVjaXNpb24gb3IgZm9ybWluZyBhbiBvcGluaW9uKS4gSW4gcGFydGljdWxhciwgTHVjZSBpbnRyb2R1Y2VkIHRoZSBheGlvbSBvZiBJbmRlcGVuZGVuY2Ugb2YgSXJyZWxldmFudCBBbHRlcm5hdGl2ZXMgKGRpc2N1c3NlZCBpbiBDaGFwdGVyIFxAcmVmKGNoYXB0ZXItMykpLiBBY2NvcmRpbmcgdG8gTWNGYWRkZW4gKDIwMDEsIHAuIDM1MyksIHRoaXMgYXhpb20gInNpbXBsaWZpZWQgZXhwZXJpbWVudGFsIGNvbGxlY3Rpb24gb2YgY2hvaWNlIGRhdGEgYnkgYWxsb3dpbmcgbXVsdGlub21pYWwgY2hvaWNlIHByb2JhYmlsaXRpZXMgdG8gYmUgaW5mZXJyZWQgZnJvbSBiaW5vbWlhbCBjaG9pY2UgZXhwZXJpbWVudHMuIiBbSi4gTWFyc2NoYWtdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0phY29iX01hcnNjaGFrKSB3YXMgdGhlIGZpcnN0IHRvIGludHJvZHVjZSB0aGUgd29yayBvZiBUaHVyc3RvbmUgdG8gZWNvbm9tZXRyaWNzIGluIDE5NjAsIGFuZCBhbHNvIGNvaW5lZCB0aGUgdGVybSBfUmFuZG9tIFV0aWxpdHkgTWF4aW1pemluZ18gKFJVTSkgdGhhdCBldmVudHVhbGx5IHByZXZhaWxlZCBvdmVyIHRoZSBjb21wYXJhdGl2ZSBqdWRnZW1lbnQgdGVybWlub2xvZ3kgb2YgVGh1cnN0b25lLiBNY0ZhZGRlbidzIGVhcmx5IGNvbnRyaWJ1dGlvbnMgdG8gdGhpcyBib2R5IG9mIHJlc2VhcmNoIHdhcyBkZXZlbG9waW5nIGFuIGVjb25vbWV0cmljIHZlcnNpb24gb2YgTHVjZSdzIG1vZGVsLCB3aXRoIHN0cmljdCAoaS5lLiwgc3lzdGVtYXRpYykgdXRpbGl0aWVzIHNwZWNpZmllZCBhcyBmdW5jdGlvbnMgb2YgdGhlIGF0dHJpYnV0ZXMgb2YgdGhlIGFsdGVybmF0aXZlcy4gVGhpcyBhbGxvd2VkIGEgcmVzZWFyY2ggdG8gbGluayB1bm9ic2VydmVkIHByZWZlcmVuY2UgaGV0ZXJvZ2VuZWl0eSB0byBhIGZ1bGx5IGNvbnNpc3RlbnQgZGVzY3JpcHRpb24gb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkZW1hbmQuIFNpbmNlIHRoZSAxOTcwcywgZGlzY3JldGUgY2hvaWNlIGFuYWx5c2lzIGhhcyBiZWVuIGEgYnVyZ2VvbmluZyBhcmVhIG9mIHJlc2VhcmNoIHdpdGggYSBwbGV0aG9yYSBvZiBhcHBsaWNhdGlvbnMgaW4gZWNvbm9taWNzLCBtYXJrZXRpbmcsIGFuZCB0cmF2ZWwgYmVoYXZpb3IsIGFtb25nIG1hbnkgb3RoZXIgZGlzY2lwbGluZXMuDQoNClRoaXMgYnJpZWYgc3RvcnkgbmVhdGx5IGlsbHVzdHJhdGVzIHRoZSBjb21wbGV4IGludGVycGxheSBiZXR3ZWVuIHRoZW9yeSBhbmQgcHJhY3RpY2UuDQoNCkVhcmx5IGF0dGVtcHRzIHRvIHN0dWR5IGRlbWFuZCB3ZXJlIGxpbWl0ZWQgZHVlIHRvIHByYWN0aWNhbCBjb25zaWRlcmF0aW9ucyAoaS5lLiwgdGhlIGFic2VuY2Ugb2YgZGF0YSBhdCB0aGUgaW5kaXZpZHVhbCBsZXZlbCkuIE9uY2UgYXBwcm9wcmlhdGUgZGF0YSBiZWNhbWUgYXZhaWxhYmxlLCBuZXcgc3R1ZGllcyBjb250aW51ZWQgdG8gcHVzaCB0aGUgdGhlb3JldGljYWwgZW52ZWxvcGUuIEluZGVlZCwgdGhlb3JldGljYWwgcXVlc3Rpb25zIGhhdmUgY29udGludWVkIHRvIGluc3BpcmUgbmV3ZXIgd2F5IHRvIGNvbGxlY3QgZGF0YSBhbmQgbm92ZWwgbWV0aG9kcywgYW5kIHRoZXNlIGluIHR1cm4gaGF2ZSBoZWxwZWQgdXMgdG8gcmVmaW5lIG91ciB1bmRlcnN0YW5kaW5nIG9mIGJlaGF2aW9yLiBTZWUgYXMgYW4gZXhhbXBsZSB0aGUgd29yayBvbiBkZWNpc2lvbi1tYWtpbmcgaW4gc29jaWFsIHNpdHVhdGlvbnMgW0BBa2VybG9mMTk5N3NvY2lhbDsgQEF4aGF1c2VuMjAwNXNvY2lhbDsgQFBhZXoyMDA3c29jaWFsXSB3aGljaCBpbnNwaXJlZCB0aGUgdXNlIG9mIG5ldyBkYXRhIHNvdXJjZXMgW2UuZy4sIEBDYXJyYXNjbzIwMDdzb2NpYWwgQEF4aGF1c2VuMjAwOHNvY2lhbDsgQFNjb3R0MjAxMnNvY2lhbDsgQENoZW4yMDE2c29jaWFsXSBhcyB3ZWxsIGFzIG5vdmVsIG1vZGVsbGluZyBhcHByb2FjaGVzIFtlLmcuLCBARHVndW5kamkyMDA1ZGlzY3JldGU7IEBEdWd1bmRqaTIwMTNzb2NpYWw7IEBLYW1hcmdpYW5uaTIwMTRzb2NpYWxdIGFuZCBlbXBpcmljYWwgd29yayBbZS5nLiwgQHZhbmRlbkJlcmcyMDA5c29jaWFsOyBAR29ldHprZTIwMTFiaWN5Y2xlOyBATWF0b3VzMjAxN3NvY2lhbF0uDQoNCk5vdyB0aGF0IHRoZSBwcmVjZWRpbmcgY2hhcHRlcnMgaGF2ZSBhcm1lZCB1cyB3aXRoIHRoZSB0aGVvcnkgYW5kIGJhc2ljIGNvbmNlcHRzIHRvIGltcGxlbWVudCByYW5kb20gdXRpbGl0eSBtb2RlbHMsIGl0IGlzIHByb3BlciB0aGF0IHdlIHR1cm4gb3VyIGF0dGVudGlvbiB0byB0aGUgcHJhY3RpY2FsIGFzcGVjdHMgb2YgbW9kZWxsaW5nLiBUaGUgYmVzdCB3YXkgdG8gZW5zdXJlIHRoYXQgdGhlIGNvbmNlcHRzIHRha2UgaG9sZCwgaW4gbXkgdmlldywgaXMgdG8gZ2V0IHlvdXIgaGFuZHMgb24gYSBkYXRhc2V0IGFuZCBzdHJ1Z2dsZSB3aXRoIHRoZSBwcmFjdGljYWxpdGllcyBvZiBjbGVhbmluZyBhbmQgb3JnYW5pemluZyBkYXRhLCBzcGVjaWZ5aW5nIHRoZSB1dGlsaXR5IGZ1bmN0aW9ucyAoYSB0YXNrIHRoYXQgaXMgbW9yZSBhcnQgdGhhbiBzY2llbmNlKSwgYW5kIGVzdGltYXRpbmcgbW9kZWxzLiBUaGVzZSBza2lsbHMgYXJlIG1vc3RseSB0cmFuc2ZlcmFibGUgdG8gb3RoZXIgbW9kZWxsaW5nIHRlY2huaXF1ZXMsIHNvIHdlIHdpbGwgYmVnaW4gYnkgYXBwbHlpbmcgdGhlbSB0byB0aGUgbW9zdCBmdW5kYW1lbnRhbCBvZiBkaXNjcmV0ZSBjaG9pY2UgbW9kZWxzLCBuYW1lbHkgdGhlIG11bHRpbm9taWFsIGxvZ2l0LiAgDQoNCiMjIEhvdyB0byB1c2UgdGhpcyBub3RlDQoNClJlbWVtYmVyIHRoYXQgdGhlIHNvdXJjZSBmb3IgdGhlIGRvY3VtZW50IHlvdSBhcmUgcmVhZGluZyBpcyBhbiBSIE5vdGVib29rLiBUaHJvdWdob3V0IHRoZSBub3RlcywgeW91IHdpbGwgZmluZCBleGFtcGxlcyBvZiBjb2RlIGluIHNlZ21lbnRzIG9mIHRleHQgY2FsbGVkIF9jaHVua3NfLiBUaGlzIGlzIGFuIGV4YW1wbGUgb2YgYSBjaHVuazoNCmBgYHtyfQ0KcHJpbnQoIkhhdHMgb2ZmIHRvIHlvdSwgUHJvZi4gTWNGYWRkZW4iKQ0KYGBgDQoNCklmIHlvdSBhcmUgd29ya2luZyB3aXRoIHRoZSBOb3RlYm9vayB2ZXJzaW9uIG9mIHRoZSBkb2N1bWVudCwgeW91IGNhbiBydW4gdGhlIGNvZGUgYnkgY2xpY2tpbmcgdGhlICdwbGF5JyBpY29uIG9uIHRoZSB0b3AgcmlnaHQgY29ybmVyIG9mIHRoZSBjaHVuay4gSWYgeW91IGFyZSByZWFkaW5nIHRoZSB3ZWItYm9vayB2ZXJzaW9uIG9mIHRoZSBkb2N1bWVudCwgeW91IHdpbGwgb2Z0ZW4gc2VlIHRoYXQgdGhlIGNvZGUgaGFzIGFscmVhZHkgYmVlbiBleGVjdXRlZC4gWW91IGNhbiBzdGlsbCB0cnkgaXQgYnkgY29weWluZyBhbmQgcGFzdGluZyBpbnRvIHlvdXIgUiBvciBSU3R1ZGlvIGNvbnNvbGUuDQoNCiMjIExlYXJuaW5nIG9iamVjdGl2ZXMNCg0KSW4gdGhpcyBwcmFjdGljZSwgeW91IHdpbGwgbGVhcm4gYWJvdXQ6DQoNCjEuIFNwZWNpZmljYXRpb24gb2YgdXRpbGl0eSBmdW5jdGlvbnMuDQoyLiBNYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbi4NCjMuIEVzdGltYXRpb24gb2YgbXVsdGlub21pYWwgbG9naXQgbW9kZWxzLg0KNC4gTWNGYWRkZW4ncyAkXHJob14yJA0KNS4gVGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdC4NCg0KIyMgU3VnZ2VzdGVkIHJlYWRpbmdzDQoNCi0gQmVuLUFraXZhLCBNLiBMZXJtYW4sIFstQEJlbmFraXZhMTk4NWRpc2NyZXRlXSBEaXNjcmV0ZSBDaG9pY2UgQW5hbHlzaXM6IFRoZW9yeSBhbmQgQXBwbGljYXRpb25zIHRvIFRyYXZlbCBEZW1hbmQsICoqQ2hhcHRlcnMgNCBhbmQgNSoqLCBNSVQgUHJlc3MuDQotIEhlbnNoZXIsIEQuQS4sIFJvc2UsIEouTS4sIEdyZWVuZSwgVy5IIFstQGhlbnNoZXIyMDA1YXBwbGllZF0gQXBwbGllZCBDaG9pY2UgQW5hbHlzaXM6IEEgUHJpbWVyLCAqKkNoYXB0ZXIgMTAqKiwgQ2FtYnJpZGdlIFVuaXZlcnNpdHkgUHJlc3MuDQotIE9ydHV6YXIgSkQsIFdpbGx1bXNlbiBMRyBbLUBPcnR1emFyMjAxMW1vZGVsbGluZ10gTW9kZWxsaW5nIFRyYW5zcG9ydCwgRm91cnRoIEVkaXRpb24sICoqQ2hhcHRlciA4KiosIEpvaG4gV2lsZXkgYW5kIFNvbnMuDQotIFRyYWluIFstQFRyYWluMjAwOWRpc2NyZXRlXSBEaXNjcmV0ZSBDaG9pY2UgTWV0aG9kcyB3aXRoIFNpbXVsYXRpb24sIFNlY29uZCBFZGl0aW9uLCAqKkNoYXB0ZXIgMyoqLCBDYW1icmlkZ2UgVW5pdmVyc2l0eSBQcmVzcy4NCg0KIyMgUHJlbGltaW5hcmllcw0KDQpMb2FkIHRoZSBwYWNrYWdlcyB1c2VkIGluIHRoaXMgc2VjdGlvbjoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZXZkKQ0KbGlicmFyeShtbG9naXQpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHBsb3RseSkNCmBgYA0KDQpMb2FkIHRoZSBkYXRhc2V0IHVzZWQgaW4gdGhpcyBzZWN0aW9uOg0KYGBge3J9DQpsb2FkKCJDb21tdXRlIE1hYy5SRGF0YSIpDQpgYGANCg0KIyMgVGhlIGFuYXRvbXkgb2YgdXRpbGl0eSBmdW5jdGlvbnMNCg0KQXQgdGhlIGVuZCBDaGFwdGVyIFxAcmVmKGNoYXB0ZXItMykgd2UgdG9vaywgZm9yIHRoZSBmaXJzdCB0aW1lLCBhIGNsb3NlciBsb29rIGF0IHRoZSBzeXN0ZW1hdGljIHV0aWxpdGllcyBvZiBkaXNjcmV0ZSBjaG9pY2UgbW9kZWxzLiBJdCBpcyB1c2VmdWwgdG8gdGhpbmsgYWJvdXQgdGhlIGFuYXRvbXkgb2YgYSB0eXBpY2FsIHN5c3RlbWF0aWMgdXRpbGl0eSBmdW5jdGlvbi4gUHJldmlvdXNseSwgd2Ugc2FpZCB0aGF0IHNvbWUgdmFyaWFibGVzIHZhcnkgYWNyb3NzIHV0aWxpdHkgZnVuY3Rpb25zOyB0aGVzZSBhcmUgdHlwaWNhbGx5IHRoZSBhdHRyaWJ1dGVzIHRoYXQgZGVzY3JpYmUgdGhlIHZhcmlvdXMgYWx0ZXJuYXRpdmVzIChlLmcuLCB0aGVpciBsZXZlbCBvZiBzZXJ2aWNlIGFuZCBjb3N0KS4gVGhlIHZhcmlhYmxlcyB0aGF0IGRlc2NyaWJlIHRoZSBkZWNpc2lvbi1tYWtlciBkbyBfbm90XyB2YXJ5IGJ5IGFsdGVybmF0aXZlLiBUaGlzIGhhcyBpbXBsaWNhdGlvbnMsIGFzIHNlZW4gYmVmb3JlLCBmb3IgaG93IHRoZSB2YXJpYWJsZXMgYXJlIGVudGVyZWQgaW50byB0aGUgZnVuY3Rpb25zLiBTaW5jZSB0aGUgbW9kZWwgd29ya3Mgb24gdGhlIGJhc2lzIG9mIF9kaWZmZXJlbmNlc18gYmV0d2VlbiB1dGlsaXRpZXMsIHRoZSBhdHRyaWJ1dGVzIG11c3QgYWN0dWFsbHkgbWVhc3VyZSBkaWZmZXJlbnQgbGV2ZWxzIG9mIHNvbWV0aGluZyBvciB2YW5pc2guDQoNCldlIHdpbGwgZGVzY3JpYmUgdGhlIHV0aWxpdGllcyBpbiB0ZXJtcyBvZiB0aGUgd2F5IGRpZmZlcmVudCB2YXJpYWJsZXMgYXJlIGludHJvZHVjZWQgaW4gdGhlIHV0aWxpdHkgZnVuY3Rpb25zLiBBcyBiZWZvcmUsIHdlIHdpbGwgYXNzdW1lIHRoYXQgdGhlIGxvY2F0aW9uIHBhcmFtZXRlcnMgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhcmUgYWJzb3JiZWQgYnkgJEotMSQgdXRpbGl0eSBmdW5jdGlvbnMgKHdoZXJlICRKJCBpcyB0aGUgbnVtYmVyIG9mIGFsdGVybmF0aXZlcykgaW4gdGhlIGZvcm0gb2YgYWx0ZXJuYXRpdmUgc3BlY2lmaWMgY29uc3RhbnRzLiANCg0KQ29uc2lkZXIgZmlyc3QgdmFyaWFibGVzIHRoYXQgdmFyeSBhY3Jvc3MgYWx0ZXJuYXRpdmVzLiBUaGVzZSB2YXJpYWJsZXMgY2FuIGhhdmUgYSBnZW5lcmljIGNvZWZmaWNpZW50IG9yIHRoZXkgY2FuIGhhdmUgYWx0ZXJuYXRpdmUtc3BlY2lmaWMgY29lZmZpY2llbnRzLCBhcyBzZWVuIGhlcmU6DQoNCiQkDQpcYmVnaW57YXJyYXl9e2x9DQogICAgICAgICAgICAgICAgVl97aTF9ID1cXA0KICAgICAgICAgICAgICAgIFZfe2kyfSA9XFwNCiAgICAgICAgICAgICAgICBWX3tpM30gPVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9ICANCiAgXG92ZXJicmFjZXsgXGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgMCAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgIDAgJiArXG11XzIgJiArMCBcXA0KICAgICAgICAgICAgICAgIDAgJiArMCAmICtcbXVfM1xcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1eXHRleHR7YWx0ZXJuYXRpdmUgc3BlY2lmaWMgY29uc3RhbnRzfSANCiAgXHVuZGVyYnJhY2V7XGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgK1xiZXRhXzF4X3tpMX1cXA0KICAgICAgICAgICAgICAgICtcYmV0YV8xeF97aTJ9XFwNCiAgICAgICAgICAgICAgICArXGJldGFfMXhfe2kzfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1fe1x0ZXh0e2FsdGVybmF0aXZlIHZhcnMuIHdpdGggZ2VuZXJpYyBjb2VmZmljaWVudHN9fQ0KICBcb3ZlcmJyYWNle1xiZWdpbnthcnJheX17bGxsfQ0KICAgICAgICAgICAgICAgICArXGRlbHRhXzF3X3tpMX0gJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICArMCAmICtcZGVsdGFfMndfe2kyfSAmICswXFwNCiAgICAgICAgICAgICAgICArMCAmICswICYgK1xkZWx0YV8zd197aTN9XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0NCiAgICAgICAgICAgICAgfV57XHRleHR7YWx0ZXJuYXRpdmUgdmFycy4gd2l0aCBzcGVjaWZpYyBjb2VmZmljaWVudHN9fQ0KJCQNCg0KSW4gbWFueSBjYXNlcyBpdCBpcyBzZW5zaWJsZSB0byBoYXZlIGdlbmVyaWMgY29lZmZpY2llbnRzLiBGb3IgaW5zdGFuY2UsIGlmIHRoZSB2YXJpYWJsZSBpcyBjb3N0LCB3ZSBtaWdodCBhc3N1bWUgdGhhdCBvbmUgZG9sbGFyIGlzIHZhbHVlZCBlcXVhbGx5IGlycmVzcGVjdGl2ZSBvZiB0aGUgd2hpY2ggYWx0ZXJuYXRpdmUgaXQgaXMgc3BlbnQgb24uIEluIG90aGVyIGNhc2VzLCB0aGUgdXNlIG9mIGFsdGVybmF0aXZlLXNwZWNpZmljIGNvZWZmaWNpZW50cyBtaWdodCBiZSBpbmZvcm1hdGl2ZS4gRm9yIGluc3RhbmNlLCBhIGNvbnNpc3RlbnQgZmluZGluZyBpbiB0aGUgbGl0ZXJhdHVyZSBpcyB0aGF0IHRpbWUgd2FpdGluZyBmb3IgYSBidXMgaXMgcGVyY2VpdmVkIGFzIGJlaW5nIG1vcmUgZXhwZW5zaXZlIHRoYW4gdGltZSBhY3R1YWxseSBvbi1ib2FyZCBhbmQgdHJhdmVsaW5nIGluIHRoZSBidXMuIE9jY2FzaW9uYWxseSwgYXMgd2VsbCwgYW4gYXR0cmlidXRlIG1pZ2h0IGJlIHNwZWNpZmljIHRvIGFuIGFsdGVybmF0aXZlOiBmb3IgaW5zdGFuY2UsIHdhaXRpbmcgdGltZSBpcyBvZnRlbiBpbXBsaWNpdGx5IHplcm8gZm9yIHRyYXZlbCBieSBjYXIgYW5kIGFjdGl2ZSBtb2RlcyBvZiB0cmFuc3BvcnRhdGlvbiAoaS5lLiwgd2Fsa2luZyBhbmQgY3ljbGluZykuDQoNClRoZSBkaWZmZXJlbmNlcyBvZiB0aGUgdXRpbGl0aWVzIGFyZSBhcyBmb2xsb3dzOg0KDQokJA0KXGJlZ2lue2FycmF5fXtsbGx9DQogICAgVl97aTJ9LVZfe2kxfT0mKFxtdV8yIC0gMCkgJiArICZcYmV0YV8xKHhfe2kyfSAtIHhfe2kxfSkgJiArICYoXGRlbHRhXzJ3X3tpMn0gLSBcZGVsdGFfMXdfe2kxfSlcXA0KICAgIFZfe2kzfS1WX3tpMX09JihcbXVfMyAtIDApICYgKyAmXGJldGFfMSh4X3tpMn0gLSB4X3tpMX0pICYgKyAmKFxkZWx0YV8zd197aTN9IC0gIFxkZWx0YV8xd197aTF9KVxcDQogICAgVl97aTN9LVZfe2kyfT0mKFxtdV8zLSBcbXVfMikgJiArICZcYmV0YV8xKHhfe2kyfSAtIHhfe2kxfSkgJiArICYoXGRlbHRhXzN3X3tpM30gLSBcZGVsdGFfMndfe2kyfSlcXA0KXGVuZHthcnJheX0NCiQkDQoNClZhcmlhYmxlcyB0aGF0IHZhcnkgYWNyb3NzIGluZGl2aWR1YWxzIGJ1dCBub3QgYnkgYWx0ZXJuYXRpdmUgY2FuIGJlIGludHJvZHVjZWQgd2l0aCBhbHRlcm5hdGl2ZS1zcGVjaWZpYyBjb2VmZmljaWVudHM6DQoNCiQkDQpcYmVnaW57YXJyYXl9e2x9DQogICAgICAgICAgICAgICAgVl97aTF9ID1cXA0KICAgICAgICAgICAgICAgIFZfe2kyfSA9XFwNCiAgICAgICAgICAgICAgICBWX3tpM30gPVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9ICANCiAgXG92ZXJicmFjZXsgXGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgMCAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgIDAgJiArXG11XzIgJiArMCBcXA0KICAgICAgICAgICAgICAgIDAgJiArMCAmICtcbXVfM1xcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1eXHRleHR7YWx0ZXJuYXRpdmUgc3BlY2lmaWMgY29uc3RhbnRzfSANCiAgXHVuZGVyYnJhY2V7XGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgK1xiZXRhXzF4X3tpMX1cXA0KICAgICAgICAgICAgICAgICtcYmV0YV8xeF97aTJ9XFwNCiAgICAgICAgICAgICAgICArXGJldGFfMXhfe2kzfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1fe1x0ZXh0e2FsdGVybmF0aXZlIHZhcnMuIHdpdGggZ2VuZXJpYyBjb2VmZmljaWVudHN9fQ0KDQogIFxvdmVyYnJhY2V7XGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgICtcZGVsdGFfMXdfe2kxfSAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgICswICYgK1xkZWx0YV8yd197aTJ9ICYgKzBcXA0KICAgICAgICAgICAgICAgICswICYgKzAgJiArXGRlbHRhXzN3X3tpM31cXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fQ0KICAgICAgICAgICAgICB9XntcdGV4dHthbHRlcm5hdGl2ZSB2YXJzLiB3aXRoIHNwZWNpZmljIGNvZWZmaWNpZW50c319DQogIFx1bmRlcmJyYWNle1xiZWdpbnthcnJheX17bGxsfQ0KICAgICAgICAgICAgICAgICswICYgKzAgJlxcDQogICAgICAgICAgICAgICAgK1xnYW1tYV8yel97aX0gJiArMFxcDQogICAgICAgICAgICAgICAgKzAgJiArXGdhbW1hXzN6X3tpfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1fXHRleHR7aW5kaXZpZHVhbCB2YXJzIHdpdGggc3BlY2lmaWMgY29lZmZpY2llbnRzfQ0KJCQNCg0KRm9sbG93aW5nIHRoZSBleGFtcGxlIGFib3ZlLCB0aGUgZGlmZmVyZW5jZXMgb2YgdXRpbGl0aWVzIGFyZToNCg0KJCQNClxiZWdpbnthcnJheX17bGxsfQ0KICAgIFZfe2kyfS1WX3tpMX09JihcbXVfMiAtIDApICYgKyAmXGJldGFfMSh4X3tpMn0gLSB4X3tpMX0pICYgKyAmKFxkZWx0YV8yd197aTJ9IC0gXGRlbHRhXzF3X3tpMX0pICYgKyAmKFxnYW1tYV8yIC0gMCl6X2lcXA0KICAgIFZfe2kzfS1WX3tpMX09JihcbXVfMyAtIDApICYgKyAmXGJldGFfMSh4X3tpMn0gLSB4X3tpMX0pICYgKyAmKFxkZWx0YV8zd197aTN9IC0gIFxkZWx0YV8xd197aTF9KSAmICsgJihcZ2FtbWFfMyAtIDApel9pXFwNCiAgICBWX3tpM30tVl97aTJ9PSYoXG11XzMtIFxtdV8yKSAmICsgJlxiZXRhXzEoeF97aTJ9IC0geF97aTF9KSAmICsgJihcZGVsdGFfM3dfe2kzfSAtIFxkZWx0YV8yd197aTJ9KSAmICsgJihcZ2FtbWFfMyAtIFxnYW1tYV8yKXpfaVxcDQpcZW5ke2FycmF5fQ0KJCQNCg0KQSBkaWZmZXJlbnQgd2F5IG9mIGludHJvZHVjaW5nIGluZGl2aWR1YWwtbGV2ZWwgdmFyaWFibGVzIGlzIGFzIHBhcnQgb2YgYW4gZXhwYW5zaW9uIG9mIHNvbWUgY29lZmZpY2llbnRzLCBmb3IgZXhhbXBsZToNCg0KJCQNCg0KXGJlZ2lue2FycmF5fXtsfQ0KICAgICAgICAgICAgICAgIFZfe2kxfSA9XFwNCiAgICAgICAgICAgICAgICBWX3tpMn0gPVxcDQogICAgICAgICAgICAgICAgVl97aTN9ID1cXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fSAgDQogIFxvdmVyYnJhY2V7IFxiZWdpbnthcnJheX17bGxsfQ0KICAgICAgICAgICAgICAgIDAgJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICAwICYgK1xtdV8yICYgKzAgXFwNCiAgICAgICAgICAgICAgICAwICYgKzAgJiArXG11XzNcXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fQ0KICAgICAgICAgICAgICB9Xlx0ZXh0e2FsdGVybmF0aXZlIHNwZWNpZmljIGNvbnN0YW50c30gDQogIFx1bmRlcmJyYWNle1xiZWdpbnthcnJheX17bGxsfQ0KICAgICAgICAgICAgICAgICsoXGJldGFfezExfSArIFxiZXRhX3sxMn16X2kpeF97aTF9XFwNCiAgICAgICAgICAgICAgICArKFxiZXRhX3sxMX0gKyBcYmV0YV97MTJ9el9pKXhfe2kyfVxcDQogICAgICAgICAgICAgICAgKyhcYmV0YV97MTF9ICsgXGJldGFfezEyfXpfaSl4X3tpM31cXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fQ0KICAgICAgICAgICAgICB9X3tcdGV4dHthbHRlcm5hdGl2ZSB2YXJzLiB3aXRoIGdlbmVyaWMgY29lZmZpY2llbnRzfX0NCiAgXG92ZXJicmFjZXtcYmVnaW57YXJyYXl9e2xsbH0NCiAgICAgICAgICAgICAgICAgK1xkZWx0YV8xd197aTF9ICYgKzAgJiArMFxcDQogICAgICAgICAgICAgICAgKzAgJiArXGRlbHRhXzJ3X3tpMn0gJiArMFxcDQogICAgICAgICAgICAgICAgKzAgJiArMCAmICtcZGVsdGFfM3dfe2kzfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1ee1x0ZXh0e2FsdGVybmF0aXZlIHZhcnMuIHdpdGggc3BlY2lmaWMgY29lZmZpY2llbnRzfX0NCiQkDQoNClRoZSBhYm92ZSBleHBhbmRzIHRvOg0KDQokJA0KDQpcYmVnaW57YXJyYXl9e2x9DQogICAgICAgICAgICAgICAgVl97aTF9ID1cXA0KICAgICAgICAgICAgICAgIFZfe2kyfSA9XFwNCiAgICAgICAgICAgICAgICBWX3tpM30gPVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9ICANCiAgXG92ZXJicmFjZXsgXGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgMCAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgIDAgJiArXG11XzIgJiArMCBcXA0KICAgICAgICAgICAgICAgIDAgJiArMCAmICtcbXVfM1xcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1eXHRleHR7YWx0ZXJuYXRpdmUgc3BlY2lmaWMgY29uc3RhbnRzfSANCiAgXHVuZGVyYnJhY2V7XGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgK1xiZXRhX3sxMX14X3tpMX0gJiArXGJldGFfezEyfXpfaXhfe2kxfVxcDQogICAgICAgICAgICAgICAgK1xiZXRhX3sxMX14X3tpMn0gJiArIFxiZXRhX3sxMn16X2l4X3tpMn1cXA0KICAgICAgICAgICAgICAgICtcYmV0YV97MTF9eF97aTN9ICYgKyBcYmV0YV97MTJ9el9peF97aTN9XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0NCiAgICAgICAgICAgICAgfV97XHRleHR7YWx0ZXJuYXRpdmUgdmFycy4gd2l0aCBnZW5lcmljIGNvZWZmaWNpZW50c319DQogIFxvdmVyYnJhY2V7XGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgK1xkZWx0YV8xd197aTF9ICYgKzAgJiArMFxcDQogICAgICAgICAgICAgICAgKzAgJiArXGRlbHRhXzJ3X3tpMn0gJiArMFxcDQogICAgICAgICAgICAgICAgKzAgJiArMCAmICtcZGVsdGFfM3dfe2kzfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1ee1x0ZXh0e2FsdGVybmF0aXZlIHZhcnMuIHdpdGggc3BlY2lmaWMgY29lZmZpY2llbnRzfX0NCiQkDQoNCkFuZCBzbyB0aGUgZGlmZmVyZW5jZXMgaW4gdXRpbGl0aWVzIGFyZToNCg0KJCQNClxiZWdpbnthcnJheX17bGxsfQ0KICAgIFZfe2kyfS1WX3tpMX09JihcbXVfMiAtIDApICYgKyAmXGJldGFfezExfSh4X3tpMn0gLSB4X3tpMX0pICYgKyAmXGJldGFfezExfSh6X2l4X3tpMn0gLSB6X2l4X3tpMX0pICYgKyAmKFxkZWx0YV8yd197aTJ9IC0gXGRlbHRhXzF3X3tpMX0pXFwNCiAgICBWX3tpM30tVl97aTF9PSYoXG11XzMgLSAwKSAmICsgJlxiZXRhX3sxMX0oeF97aTJ9IC0geF97aTF9KSAmICsgJlxiZXRhX3sxMX0oel9peF97aTN9IC0gel9peF97aTF9KSAmICsgJihcZGVsdGFfM3dfe2kzfSAtICBcZGVsdGFfMXdfe2kxfSlcXA0KICAgIFZfe2kzfS1WX3tpMn09JihcbXVfMy0gXG11XzIpICYgKyAmXGJldGFfezExfSh4X3tpMn0gLSB4X3tpMX0pICYgKyAmXGJldGFfezExfSh6X2l4X3tpM30gLSB6X2l4X3tpMn0pICYgKyAmKFxkZWx0YV8zd197aTN9IC0gXGRlbHRhXzJ3X3tpMn0pXFwNClxlbmR7YXJyYXl9DQokJA0KDQpVbmRlcnN0YW5kaW5nIHRoZSBhbmF0b215IG9mIHV0aWxpdHkgZnVuY3Rpb25zIGlzIGVzc2VudGlhbCB0byBwcm9wZXJseSBzcGVjaWZ5IGFuZCBlc3RpbWF0ZSBtb2RlbHMuDQoNCiMjIEV4YW1wbGU6IFNwZWNpZnlpbmcgdGhlIHV0aWxpdHkgZnVuY3Rpb25zDQoNCldlIHdpbGwgbm93IHByb2NlZWQgdG8gd29yayB3aXRoIGEgcHJhY3RpY2FsIGV4YW1wbGUsIHVzaW5nIHRoZSBkYXRhc2V0IHRoYXQgeW91IGVuY291bnRlcmVkIGJlZm9yZSBpbiBDaGFwdGVyIFxAcmVmKGNoYXB0ZXItMSkuIFRoaXMgZGF0YXNldCBjb250YWlucyBpbmZvcm1hdGlvbiBvbiB2YXJpb3VzIG1vZGVzIG9mIHRyYW5zcG9ydGF0aW9uIHVzZWQgYnkgcGVvcGxlIGNvbW11dGluZyB0byBNY01hc3RlciBVbml2ZXJzaXR5IGluIENhbmFkYSBbQFdoYWxlbjIwMTNdLiBUaGUgZGF0YXNldCB3YXMgbG9hZGVkIGFib3ZlIGFzIHBhcnQgb2YgdGhlIHByZWxpbWluYXJpZXMgb2YgdGhpcyBjaGFwdGVyLiBXZSBjYW4gYmVnaW4gYnkgZXhwbG9yaW5nIHRoZSBkYXRhLiBGaXJzdCwgd2Ugbm90aWNlIHRoYXQgdGhpcyBpcyBhIGRhdGFmcmFtZSB0aGF0IGhhcyBiZWVuIHByZXBhcmVkIGZvciB1c2Ugd2l0aCB0aGUgYG1sb2dpdGAgcGFja2FnZToNCmBgYHtyfQ0KY2xhc3MobWNfY29tbXV0ZSkNCmBgYA0KDQpQbGVhc2Ugbm90ZSB0aGF0IHRoaXMgaXMgdGhlIHNhbWUgZGF0YXNldCB0aGF0IHlvdSB1c2VkIGluIENoYXB0ZXIgXEByZWYoY2hhcHRlci0xKSwgYnV0IG5vdCB0aGUgc2FtZSBmaWxlLiBGb3IgY29udmVuaWVuY2UsIHRoZSBkYXRhc2V0IHdhcyBwcmUtcHJvY2Vzc2VkIGZvciB1c2Ugd2l0aCBgbWxvZ2l0YC4gVGhlIGNvbnRlbnRzIG9mIHRoZSBkYXRhZnJhbWUgY2FuIGJlIHF1aWNrbHkgc2VlbiBieSBtZWFucyBvZiB0aGUgZnVuY3Rpb24gYGhlYWQoKWAuIFRoaXMgZnVuY3Rpb24gd2lsbCBkaXNwbGF5IHRoZSBmaXJzdCBmZXcgdG9wIHJvd3Mgb2YgdGhlIGRhdGFmcmFtZToNCmBgYHtyfQ0KaGVhZChtY19jb21tdXRlLCA4KQ0KYGBgDQoNCkFzIHlvdSBjYW4gc2VlLCB0aGUgZGF0YWZyYW1lIGhhcyBiZWVuIG9yZ2FuaXplZCBpbiBhIHBhcnRpY3VsYXIgd2F5LiBOb3csIGluc3RlYWQgb2YgZWFjaCByb3cgYmVpbmcgYW4gaW5kaXZpZHVhbCwgZWFjaCByb3cgaXMgYSBjaG9pY2Ugc2l0dWF0aW9uLiBTaW5jZSB0aGVyZSBhcmUgZm91ciBhbHRlcm5hdGl2ZXMgaW4gdGhpcyBjYXNlLCBlYWNoIHJvdyBjb3JyZXNwb25kcyB0byB0aGUgY2hvaWNlIHNpdHVhdGlvbiBmb3IgYW4gYWx0ZXJuYXRpdmUgZm9yIGFuIGluZGl2aWR1YWwuIFdlIG5vdGljZSB0aGF0IHRoZSByb3cgbmFtZXMgbm93IGhhdmUgdGhlIGZvcm1hdCBgIy5BbHRgLCB3aGVyZSBgI2AgaXMgdGhlIG51bWJlciBvZiB0aGUgZGVjaXNpb24gbWFrZXIgYW5kIGBBbHRgIGlzIHRoZSBuYW1lIG9mIHRoZSBhbHRlcm5hdGl2ZS4gSW4gdGhpcyB3YXkgdGhlIGZpcnN0IGZvdXIgcm93cyBvZiB0aGUgdGFibGUgY29ycmVzcG9uZCB0byB0aGUgZmlyc3QgZGVjaXNpb24tbWFrZXIgd2hvLCBmYWNlZCB3aXRoIGZvdXIgYWx0ZXJuYXRpdmVzLCBjaG9zZSBIU1IgKHB1YmxpYyB0cmFuc3BvcnRhdGlvbikgLSBhcyByZWNvcmRlZCBpbiB0aGUgY29sdW1uIGBjaG9pY2VgLiBUaGUgbmV4dCBmb3VyIHJvd3MgY29ycmVzcG9uZCB0byB0aGUgc2Vjb25kIGRlY2lzaW9uLW1ha2VyIGluIHRoZSBzYW1wbGUgKHdobyBhbHNvIGNob3NlIEhTUiksIGFuZCBzbyBvbiwgZm91ciByb3dzIHBlciBkZWNpc2lvbi1tYWtlci4gTW9yZSBnZW5lcmFsbHksIHRoZXJlIHdpbGwgYmUgJEokIHJvd3MgcGVyIGRlY2lzaW9uLW1ha2VyLCB1bmxlc3Mgbm90IGFsbCBhbHRlcm5hdGl2ZXMgd2VyZSBub3QgYXZhaWxhYmxlIHRvIGFsbCBpbmRpdmlkdWFscyBpbiB0aGUgc2FtcGxlLiBNb3JlIG9uIHRoaXMgbGF0ZXIuDQoNClRoZSBmaXJzdCBzdGVwIHRvd2FyZHMgZGV2ZWxvcGluZyBhIGNob2ljZSBtb2RlbCBpcyB0byBzcGVjaWZ5IHRoZSB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgdGhlIGRlc2lyZWQgbW9kZWwuIFRoZSBwYWNrYWdlIGBtbG9naXRgIHVzZXMgdGhlIHBhY2thZ2UgYG1Gb3JtdWxhYCB0byBjcmVhdGUgdGhlIGZ1bmN0aW9ucy4gVGhpcyBwYWNrYWdlIGNyZWF0ZXMgb2JqZWN0cyB0aGF0IGJ1aWxkIHVwb24gdGhlIFtgRm9ybXVsYWAgcGFja2FnZV0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1Gb3JtdWxhICkgZm9yIG11bHRpLWNvbXBvbmVudCBmb3JtdWxhcy4gQXMgc2VlbiBhYm92ZSwgdXRpbGl0eSBmdW5jdGlvbnMgY2FuIHBvdGVudGlhbGx5IGhhdmUgbXVsdGlwbGUgY29tcG9uZW50cywgc28gdGhlIGZ1bmN0aW9uYWxpdHkgdG8gYnVpbGQgZm9ybXVsYXMgaW4gYG1Gb3JtdWxhYCBhbmQgYEZvcm11bGFgIGlzIHF1aXRlIHVzZWZ1bC4NCg0KRm9ybXVsYXMgZm9yIHRoZSBgbWxvZ2l0YCBwYWNrYWdlIGFyZSBkZWZpbmVkIHVzaW5nIHRocmVlIHBhcnRzOg0KDQokJA0KXHRleHR7Y2hvaWNlfSBcc2ltIFx0ZXh0e2FsdGVybmF0aXZlIHNwZWNpZmljIHZhcnMgd2l0aCBnZW5lcmljIGNvZWZmaWNpZW50cyB9fFx0ZXh0eyBpbmRpdmlkdWFsIHNwZWNpZmljIHZhcnMgfXxcdGV4dHsgYWx0ZXJuYXRpdmUgc3BlY2lmaWMgdmFycyB3aXRoIHNwZWNpZmljIGNvZWZmaWNpZW50c30gIA0KJCQNCg0KSWYgd2UgbGlzdCBhbGwgY29sdW1ucyBpbiB0aGUgZGF0YWZyYW1lLCB3ZSBjYW4gc2VlIHdoYXQgdmFyaWFibGVzIGFyZSBhdmFpbGFibGUgZm9yIHRoaXMgYW5hbHlzaXM6DQpgYGB7cn0NCmNvbG5hbWVzKG1jX2NvbW11dGUpDQpgYGANCg0KQmVzaWRlcyBpZGVudGlmaWVyIHZhcmlhYmxlcyBgaWRgIGFuZCBgY2hpZGAsIGFuZCB0aGUgdmFyaWFibGUgZm9yIGBjaG9pY2VgLCB3ZSBzZWUgdGhhdCBzZXZlcmFsIHZhcmlhYmxlcyBhcmUgc3BlY2lmaWMgdG8gdGhlIGluZGl2aWR1YWwgZGVjaXNpb24tbWFrZXJzLiBUaGVzZSBhcmUgYHBhcmtpbmdgIChhdmFpbGFiaWxpdHkgb2YgYSBwYXJraW5nIHBhc3MpLCBgdmVoaW5kYCAod2hldGhlciB0aGUgZGVjaXNpb24tbWFrZXIgaGFzIGluZGl2aWR1YWwgYWNjZXNzIHRvIGEgcHJpdmF0ZSB2ZWhpY2xlKSwgYGdlbmRlcmAsIGBhZ2VgLCBgc2hhcmVkYCAobGl2aW5nIGluIHNoYXJlZCBhY2NvbW1vZGF0aW9ucyBhd2F5IGZyb20gdGhlIGZhbWlseSBob21lKSwgYGZhbWlseWAgKGxpdmluZyBhdCB0aGUgZmFtaWx5IGhvbWUpLCBhbmQgYGNoaWxkYCAobWlub3JzIGFyZSBwcmVzZW50IGluIHRoZSBob3VzZWhvbGQpLiBGdXJ0aGVybW9yZSwgc29tZSB2YXJpYWJsZXMgcmVsYXRlIHRvIHRoZSBwaHlzaWNhbCBlbnZpcm9ubWVudCBvZiB0aGUgcGxhY2Ugb2YgcmVzaWRlbmNlIChgc3RyZWV0X2RlbnNpdHlgIGFuZCBgc2lkZXdhbGtfZGVuc2l0eWApLCBpbiBhZGRpdGlvbiB0byB0aGUgY29vcmRpbmF0ZXMgb2YgdGhlIHBsYWNlIG9mIHJlc2lkZW5jZSAoZ2VvY29kZWQgdG8gdGhlIG5lYXJlc3QgbWFqb3IgaW50ZXJzZWN0aW9uIG9yIHBvc3RhbCBjb2RlIGNlbnRyb2lkKS4gT25lIHZhcmlhYmxlIGlzIGFsdGVybmF0aXZlIHNwZWNpZmljLCBuYW1lbHkgYHRpbWVgICh0cmF2ZWwgdGltZSBpbiBtaW51dGVzKS4gQW5kIHRocmVlIHZhcmlhYmxlcyBhcmUgc3BlY2lmaWMgdG8gcHVibGljIHRyYW5zcG9ydGF0aW9uLCBuYW1lbHkgYEhTUi5hY2Nlc3NgIChhY2Nlc3MgdGltZSB0byBwdWJsaWMgdHJhbnNwb3J0YXRpb24gaW4gbWludXRlcyksIGBIU1Iud2FpdGAgKHdhaXRpbmcgdGltZSBpbiBtaW51dGVzKSwgYW5kIGBIU1IudHJhbnNmZXJgIChudW1iZXIgb2YgdHJhbnNmZXJzIHdoZW4gdHJhdmVsaW5nIGJ5IHB1YmxpYyB0cmFuc3BvcnRhdGlvbikuIA0KDQpXZSBjYW4gYmVnaW4gYnkgZGVmaW5pbmcgYSB2ZXJ5IHNpbXBsZSBmb3JtdWxhIHRoYXQgY29uc2lkZXJzIG9ubHkgdHJhdmVsIHRpbWUuIFdlIHdpbGwgc2F2ZSB0aGlzIG9iamVjdCBhcyBgZjFgOg0KYGBge3J9DQpmMSA8LSBtRm9ybXVsYShjaG9pY2UgfiB0aW1lKQ0KYGBgDQoNClRoZSBmdW5jdGlvbiBgbW9kZWwubWF0cml4YCBhbGxvd3MgdXMgdG8gc2VlIGhvdyB0aGUgZm9ybXVsYSBpcyBhcHBsaWVkIHRvIHRoZSBkYXRhICh3ZSB1c2UgYGhlYWQoKWAgdG8gZGlzcGxheSBvbmx5IHRoZSB0b3Agcm93cyBvZiB0aGUgbW9kZWwgbWF0cml4KToNCmBgYHtyfQ0KaGVhZChtb2RlbC5tYXRyaXgoZjEsIG1jX2NvbW11dGUpLCA4KQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgZm9ybXVsYSBpbmNsdWRlcyBieSBkZWZhdWx0IHRoZSBhbHRlcm5hdGl2ZSBzcGVjaWZpYyBjb2VmZmljaWVudHMsIGluIHRoaXMgY2FzZSB1c2luZyBhcyB0aGUgbW9kZSBjeWNsaW5nIGFzIHRoZSByZWZlcmVuY2UgYWx0ZXJuYXRpdmUuIFRoZSBjb3JyZXNwb25kaW5nIHV0aWxpdHkgZnVuY3Rpb25zIGFyZSBhcyBmb2xsb3dzOg0KDQokJA0KXGJlZ2lue2FycmF5fXtsfQ0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtDeWNsZX19ID1cXA0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtXYWxrfX0gPVxcDQogICAgICAgICAgICAgICAgVl97aVx0ZXh0e0hTUn19ID1cXA0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtIU1J9fSA9XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0gIA0KICBcb3ZlcmJyYWNleyBcYmVnaW57YXJyYXl9e2xsbH0NCiAgICAgICAgICAgICAgICAwICYgKzAgJiArMFxcDQogICAgICAgICAgICAgICAgXG11X3tcdGV4dHtXYWxrfX0gJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICAwICYgK1xtdV97XHRleHR7SFNSfX0gJiArMCBcXA0KICAgICAgICAgICAgICAgIDAgJiArMCAmICtcbXVfe1x0ZXh0e0Nhcn19XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0NCiAgICAgICAgICAgICAgfV5cdGV4dHthbHRlcm5hdGl2ZSBzcGVjaWZpYyBjb25zdGFudHN9IA0KICBcdW5kZXJicmFjZXtcYmVnaW57YXJyYXl9e2xsbH0NCiAgICAgICAgICAgICAgICArXGJldGFfMVx0ZXh0e3RpbWV9X3tpXHRleHR7Q3ljbGV9fVxcDQogICAgICAgICAgICAgICAgK1xiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e1dhbGt9fVxcDQogICAgICAgICAgICAgICAgK1xiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0hTUn19XFwNCiAgICAgICAgICAgICAgICArXGJldGFfMVx0ZXh0e3RpbWV9X3tpXHRleHR7Q2FyfX1cXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fQ0KICAgICAgICAgICAgICB9X3tcdGV4dHthbHRlcm5hdGl2ZSB2YXJzLiB3aXRoIGdlbmVyaWMgY29lZmZpY2llbnRzfX0NCiQkDQoNCkRlZmluZSBub3cgYSBmb3JtdWxhIHdpdGggYW4gaW5kaXZpZHVhbC1zcGVjaWZpYyB2YXJpYWJsZSwgc2F5IGFnZSwgYW5kIGNhbGwgaXQgYGYyYDoNCmBgYHtyfQ0KZjIgPC0gbUZvcm11bGEoY2hvaWNlIH4gdGltZSB8IGFnZSkNCmBgYA0KDQpUaGUgbW9kZWwgbWF0cml4IGlzIG5vdzoNCmBgYHtyfQ0KaGVhZChtb2RlbC5tYXRyaXgoZjIsIG1jX2NvbW11dGUpLCA4KQ0KYGBgDQoNCkFuZCB0aGUgdXRpbGl0eSBmdW5jdGlvbnMgYXJlIHRoZXJlZm9yZToNCg0KJCQNClxiZWdpbnthcnJheX17bH0NCiAgICAgICAgICAgICAgICBWX3tpXHRleHR7Q3ljbGV9fSA9XFwNCiAgICAgICAgICAgICAgICBWX3tpXHRleHR7V2Fsa319ID1cXA0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtIU1J9fSA9XFwNCiAgICAgICAgICAgICAgICBWX3tpXHRleHR7SFNSfX0gPVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9ICANCiAgXG92ZXJicmFjZXsgXGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgMCAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgIFxtdV97XHRleHR7V2Fsa319ICYgKzAgJiArMFxcDQogICAgICAgICAgICAgICAgMCAmICtcbXVfe1x0ZXh0e0hTUn19ICYgKzAgXFwNCiAgICAgICAgICAgICAgICAwICYgKzAgJiArXG11X3tcdGV4dHtDYXJ9fVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1eXHRleHR7YWx0ZXJuYXRpdmUgc3BlY2lmaWMgY29uc3RhbnRzfSANCiAgXHVuZGVyYnJhY2V7XGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgK1xiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0N5Y2xlfX1cXA0KICAgICAgICAgICAgICAgICtcYmV0YV8xXHRleHR7dGltZX1fe2lcdGV4dHtXYWxrfX1cXA0KICAgICAgICAgICAgICAgICtcYmV0YV8xXHRleHR7dGltZX1fe2lcdGV4dHtIU1J9fVxcDQogICAgICAgICAgICAgICAgK1xiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0Nhcn19XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0NCiAgICAgICAgICAgICAgfV97XHRleHR7YWx0ZXJuYXRpdmUgdmFycy4gd2l0aCBnZW5lcmljIGNvZWZmaWNpZW50c319DQogIFxvdmVyYnJhY2V7IFxiZWdpbnthcnJheX17bGxsfQ0KICAgICAgICAgICAgICAgIDAgJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICBcZ2FtbWFfezF9XHRleHR7YWdlfV97aX0gJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICAwICYgKyBcZ2FtbWFfezJ9XHRleHR7YWdlfV97aX0gJiArMCBcXA0KICAgICAgICAgICAgICAgIDAgJiArMCAmICtcZ2FtbWFfezN9XHRleHR7YWdlfV97aX1cXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fQ0KICAgICAgICAgICAgICB9Xlx0ZXh0e2luZGl2aWR1YWwgdmFycyB3aXRoIHNwZWNpZmljIGNvZWZmaWNpZW50c30gDQokJA0KDQpIZXJlLCB3ZSB0cnkgYSBkaWZmZXJlbnQgZm9ybXVsYSwgd2hlcmUgdGltZSBoYXMgYWx0ZXJuYXRpdmUtc3BlY2lmaWMgaW5zdGVhZCBvZiBnZW5lcmljIGNvZWZmaWNpZW50cywgYW5kIGNhbGwgaXQgYGYzYDoNCmBgYHtyfQ0KZjMgPC0gbUZvcm11bGEoY2hvaWNlIH4gMCB8IGFnZSB8IHRpbWUpDQpgYGANCg0KTm90ZSB0aGF0LCBzaW5jZSB3ZSBkbyBub3QgZGVmaW5lIG90aGVyIGFsdGVybmF0aXZlLXNwZWNpZmljIHZhcmlhYmxlcyB3aXRoIGdlbmVyaWMgY29lZmZpY2llbnRzLCB3ZSBoYXZlIHRvIGV4cGxpY2l0bHkgc3RhdGUgdGhhdCB0aGVyZSBhcmUgYDBgIHN1Y2ggdmFyaWFibGVzIQ0KDQpUaGlzIGZvcm11bGEgbGVhZHMgdG8gdGhlIGZvbGxvd2luZyBtb2RlbCBtYXRyaXg6DQpgYGB7cn0NCmhlYWQobW9kZWwubWF0cml4KGYzLCBtY19jb21tdXRlKSwgOCkNCmBgYA0KDQpUaGUgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHRoaXMgYXJlOg0KDQokJA0KXGJlZ2lue2FycmF5fXtsfQ0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtDeWNsZX19ID1cXA0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtXYWxrfX0gPVxcDQogICAgICAgICAgICAgICAgVl97aVx0ZXh0e0hTUn19ID1cXA0KICAgICAgICAgICAgICAgIFZfe2lcdGV4dHtIU1J9fSA9XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0gIA0KICBcb3ZlcmJyYWNleyBcYmVnaW57YXJyYXl9e2xsbH0NCiAgICAgICAgICAgICAgICAwICYgKzAgJiArMFxcDQogICAgICAgICAgICAgICAgXG11X3tcdGV4dHtXYWxrfX0gJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICAwICYgK1xtdV97XHRleHR7SFNSfX0gJiArMCBcXA0KICAgICAgICAgICAgICAgIDAgJiArMCAmICtcbXVfe1x0ZXh0e0Nhcn19XFwNCiAgICAgICAgICAgICAgXGVuZHthcnJheX0NCiAgICAgICAgICAgICAgfV5cdGV4dHthbHRlcm5hdGl2ZSBzcGVjaWZpYyBjb25zdGFudHN9IA0KICBcdW5kZXJicmFjZXsgXGJlZ2lue2FycmF5fXtsbGx9DQogICAgICAgICAgICAgICAgMCAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgIFxnYW1tYV97MX1cdGV4dHthZ2V9X3tpfSAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgIDAgJiArIFxnYW1tYV97Mn1cdGV4dHthZ2V9X3tpfSAmICswIFxcDQogICAgICAgICAgICAgICAgMCAmICswICYgK1xnYW1tYV97M31cdGV4dHthZ2V9X3tpfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9DQogICAgICAgICAgICAgIH1fXHRleHR7aW5kaXZpZHVhbCB2YXJzIHdpdGggc3BlY2lmaWMgY29lZmZpY2llbnRzfSANCiAgXG92ZXJicmFjZXtcYmVnaW57YXJyYXl9e2xsbH0NCiAgICAgICAgICAgICAgICArXGRlbHRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0N5Y2xlfX0gJiArMCAmICswICYgKzBcXA0KICAgICAgICAgICAgICAgICswICYgK1xkZWx0YV8yXHRleHR7dGltZX1fe2lcdGV4dHtXYWxrfX0gJiArMCAmICswXFwNCiAgICAgICAgICAgICAgICArMCAmICswICYgICtcZGVsdGFfM1x0ZXh0e3RpbWV9X3tpXHRleHR7SFNSfX1cXA0KICAgICAgICAgICAgICAgICswICYgKzAgJiArMCAmICtcZGVsdGFfNFx0ZXh0e3RpbWV9X3tpXHRleHR7Q2FyfX1cXA0KICAgICAgICAgICAgICBcZW5ke2FycmF5fQ0KICAgICAgICAgICAgICB9XntcdGV4dHthbHRlcm5hdGl2ZSB2YXJzLiB3aXRoIHNwZWNpZmljIGNvZWZmaWNpZW50c319DQoNCiQkDQoNCkdpdmVuIHRoZSB1dGlsaXR5IGZ1bmN0aW9ucywgdGhlIGxvZ2l0IHByb2JhYmlsaXRpZXMgZm9yIGVhY2ggYWx0ZXJuYXRpdmUgYXJlOg0KDQokJA0KXGJlZ2lue2FycmF5fXtsfQ0KICAgIFAoXHRleHR7Q3ljbGV9KSA9IFxmcmFje2Vee1Zfe1x0ZXh0e0N5Y2xlfX19fXtlXntWX3tcdGV4dHtDeWNsZX19fStlXntWX3tcdGV4dHtXYWxrfX19K2Vee1Zfe1x0ZXh0e0hTUn19fStlXntWX3tcdGV4dHtDYXJ9fX19XFwNCiAgICBQKFx0ZXh0e1dhbGt9KSA9IFxmcmFje2Vee1Zfe1x0ZXh0e1dhbGt9fX19e2Vee1Zfe1x0ZXh0e0N5Y2xlfX19K2Vee1Zfe1x0ZXh0e1dhbGt9fX0rZV57Vl97XHRleHR7SFNSfX19K2Vee1Zfe1x0ZXh0e0Nhcn19fX1cXA0KICAgIFAoXHRleHR7SFNSfSkgPSBcZnJhY3tlXntWX3tcdGV4dHtDeWNsZX19fX17ZV57Vl97XHRleHR7Q3ljbGV9fX0rZV57Vl97XHRleHR7V2Fsa319fStlXntWX3tcdGV4dHtIU1J9fX0rZV57Vl97XHRleHR7Q2FyfX19fVxcDQogICAgUChcdGV4dHtDYXJ9KSA9MSAtIFAoXHRleHR7Q3ljbGV9KSAtIFAoXHRleHR7V2Fsa30pIC0gUChcdGV4dHtIU1J9KVxcDQpcZW5ke2FycmF5fQ0KJCQNCg0KVGhlIHV0aWxpdHkgZnVuY3Rpb25zIGRlcGVuZCBvbiB0aGUgZGF0YSBidXQgYWxzbyBvbiB0aGUgY29lZmZpY2llbnRzLCB3aGljaCB3ZSBkbyBub3Qga25vdyBfYSBwcmlvcmlfLiBSYXRoZXIsIHRoZXNlIG11c3QgYmUgcmV0cmlldmVkIGZyb20gdGhlIHNhbXBsZSwgYXMgZGlzY3Vzc2VkIG5leHQuDQoNCiMjIEVzdGltYXRpb24NCg0KQmVmb3JlIHdlIGNhbiBjYWxjdWxhdGUgdGhlIGNob2ljZSBwcm9iYWJpbGl0aWVzLCB3ZSBuZWVkIHRvIHNvbWVob3cgb2J0YWluIGNvZWZmaWNpZW50cyBmb3IgdGhlIHV0aWxpdHkgZnVuY3Rpb25zLiBUaGUgcHJvY2VzcyB0byBkbyBzbyBpcyBjYWxsZWQgX2VzdGltYXRpb25fLCBhbmQgaXQgaW52b2x2ZXMgdGhlIHVzZSBvZiBhIHN0YXRpc3RpY2FsIHNhbXBsZS4gDQoNClRvIGVzdGltYXRlIHRoZSBjb2VmZmljaWVudHMgb2YgYSBtb2RlbCB3ZSBuZWVkIHRvIGRlZmluZSBhIGNyaXRlcmlvbiB0aGF0IHdlIHdpc2ggdG8gc2F0aXNmeSB3aXRoIG91ciBjaG9pY2Ugb2YgY29lZmZpY2llbnRzLiBFc3RpbWF0ZXMgY2FuIHRha2UgYW4gaW5maW5pdGUgbnVtYmVyIG9mIHZhbHVlcywgYWZ0ZXIgYWxsLCBzbyBvdXIgY3JpdGVyaW9uIG11c3QgYmUgb3B0aW1hbCBpbiBzb21lIHNlbnNlIC0gaW4gdGhpcyB3YXksIG9uY2UgdGhhdCB3ZSBlc3RpbWF0ZSB0aGUgY29lZmZpY2llbnRzIHdlIGNhbiBiZSBzYXRpc2ZpZWQgdGhhdCB0aGV5IGFyZSB0aGUgYmVzdCB0aGF0IHdlIGNhbiBvYnRhaW4gZm9yIHRoZSBtb2RlbCB1bmRlciBjb25zaWRlcmF0aW9ucywgZ2l2ZW4gdGhlbiBpbnB1dHMuDQoNCkEgY29tbW9uIGNyaXRlcmlvbiB1c2VkIHRvIGVzdGltYXRlIGRpc2NyZXRlIGNob2ljZSBtb2RlbHMgaXMgdGhlIF9saWtlbGlob29kXy4gU28gd2hhdCBpcyB0aGlzIGxpa2VsaWhvb2Q/IFByZXZpb3VzbHkgd2UgZW5jb3VudGVyZWQgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uIGZ1bmN0aW9ucy4gVGhlc2UgZnVuY3Rpb25zIHdlcmUgZGVmaW5lZCBieSBwYXJhbWV0ZXJzIChzdWNoIGFzIHRoZSBsb2NhdGlvbiBwYXJhbWV0ZXIgYW5kIHRoZSBkaXNwZXJzaW9uIHBhcmFtZXRlcikuIEdpdmVuIHRoZSBwYXJhbWV0ZXJzLCBpdCBpcyBwb3NzaWJsZSB0byBjYWxjdWxhdGUgdGhlIHByb2JhYmlsaXR5IG9mIHZhbHVlcyBmb3IgYSB2YXJpYWJsZSAkeCQuIEEgbGlrZWxpaG9vZCBmdW5jdGlvbiBpcyBhIHNpbWlsYXIgY29uY2VwdCwgZXhjZXB0IHRoYXQgd2hlcmVhcyBpbiB0aGUgcHJvYmFiaWxpdHkgZnVuY3Rpb25zIHRoZSBwYXJhbWV0ZXJzIHdlcmUgZ2l2ZW4sIGluIGEgbGlrZWxpaG9vZCBmdW5jdGlvbiB0aGUgZGF0YSBhcmUgZ2l2ZW4gYW5kIHRoZSBwYXJhbWV0ZXJzIG5lZWQgdG8gYmUgb2J0YWluZWQgZnJvbSB0aGUgZnVuY3Rpb24uDQoNClRoZSByZWxldmFudCBsaWtlbGlob29kIGZ1bmN0aW9uIGZvciB0aGUgbXVsdGlub21pYWwgbG9naXQgbW9kZWwgaXMgYXMgZm9sbG93czoNCiQkDQpMID0gXHByb2Rfe2k9bn1eTlxwcm9kX3tqPTF9XkogUF97aWp9Xnt5X3tpan19DQokJA0Kd2hlcmUgJFBfe2lqfSQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIGRlY2lzaW9uLW1ha2VyICRpJCBzZWxlY3RpbmcgYWx0ZXJuYXRpdmUgJGokIGFuZCAkeV97aWp9JCBpcyBhbiBpbmRpY2F0b3IgdmFyaWFibGUgdGhhdCB0YWtlcyB0aGUgdmFsdWUgb2YgJDEkIGlmIGluZGl2aWR1YWwgJGkkIGNob3NlIGFsdGVybmF0aXZlICRqJCBhbmQgJDAkIG90aGVyd2lzZS4gVGhlIGVmZmVjdCBvZiB0aGUgaW5kaWNhdG9yIHZhcmlhYmxlIGlzIHRvIHR1cm4gdGhlIHByb2JhYmlsaXRpZXMgb24gYW5kIG9mZiwgc2luY2UgJFBeMCA9IDEkIGFuZCAkUF4xID0gUCQuIE5vdGljZSB0aGF0IHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIGlzIGJvdW5kZWQgYmV0d2VlbiAwIGFuZCAxLCBidXQgaW4gdGhlIGNhc2Ugb2YgdGhlIGxvZ2l0IG1vZGVsIGl0IGlzIG5ldmVyIGV4YWN0bHkgemVybyBub3Igb25lLCBzaW5jZSB0aGUgbG9naXQgcHJvYmFiaWxpdGllcyBuZXZlciB0YWtlIGFueSBvZiB0aG9zZSBleGFjdCB2YWx1ZXMuDQoNCldlIGNhbiBleHBsb3JlIHRoZSBiZWhhdmlvciBvZiB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBieSBtZWFucyBvZiBhIHNpbXBsZSBleGFtcGxlLiBDb25zaWRlciBhIGJpbm9taWFsIGxvZ2l0IG1vZGUsIHRoYXQgaXMsIGEgbW9kZWwgd2l0aCBvbmx5IHR3byBhbHRlcm5hdGl2ZXMgaW4gdGhlIGNob2ljZSBzZXQuIFRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIG9mIHRoaXMgbW9kZWwgaXMgYXMgZm9sbG93czoNCg0KJCQNCkwgPSBccHJvZF97aT1ufV5OIFBfe2lBfV57eV97aUF9fVBfe2lCfV57eV97aUJ9fSA9IFxwcm9kX3tpPW59Xk4gDQogICAgXEJpZ2coXGZyYWN7ZV57Vl97aUF9fX17ZV57Vl97aUF9fSArIGVee1Zfe2lCfX19XEJpZ2cpXnt5X3tpQX19DQogICAgXEJpZ2coXGZyYWN7ZV57Vl97aUJ9fX17ZV57Vl97aUF9fSArIGVee1Zfe2lCfX19XEJpZ2cpXnt5X3tpQn19DQokJA0KDQpUaGUgdXRpbGl0eSBmdW5jdGlvbnMgJFZfe2lBfSQgYW5kICRWX3tpQn0kIGRlcGVuZCBvbiB0aGUgZGF0YSwgd2hpY2ggd2Uga25vdyAoc2luY2Ugd2UgaGF2ZSBhIHN0YXRpc3RpY2FsIHNhbXBsZSksIGFuZCB0aGUgY29lZmZpY2llbnRzLCB3aGljaCB3ZSBkbyBub3Qga25vdy4gDQoNCkZvciB0aGUgZXhhbXBsZSwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nIHRveSBzYW1wbGUgd2l0aCBzaXggaW5kaXZpZHVhbHM6DQpgYGB7ciBlY2hvPUZBTFNFfQ0KdHMgPC0gZGF0YS5mcmFtZShJbmRpdmlkdWFsID0gYygxLCAyLCAzLCA0LCA1LCA2KSwNCiAgICAgICAgICAgICAgICAgQ2hvaWNlID0gYygiQSIsICJBIiwgIkIiLCAiQSIsICJCIiwgIkIiKSwgDQogICAgICAgICAgICAgICAgIHlpQSA9IGMoMSwgMSwgMCwgMSwgMCwgMCksDQogICAgICAgICAgICAgICAgIHlpQiA9IGMoMCwgMCwgMSwgMCwgMSwgMSksDQogICAgICAgICAgICAgICAgIHhpQSA9IGMoNSwgMiwgNSwgMSwgNCwgMyksDQogICAgICAgICAgICAgICAgIHhpQiA9IGMoNCwgNSwgMiwgNiwgMSwgNCkpDQogIA0Ka2FibGUodHMsICJodG1sIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpDQpgYGANCg0KQmFzZWQgb24gdGhpcyBzYW1wbGUsIHdlIGNhbiBzcGVjaWZ5IHRoZSB1dGlsaXR5IGZ1bmN0aW9ucyBpbiB0aGlzIGZhc2hpb246DQoNCiQkDQpcYmVnaW57YXJyYXl9e2x9DQogICAgICAgICAgICAgICAgVl97aUF9ID0gMCAmKyYgXGJldGEgeF97aUF9XFwNCiAgICAgICAgICAgICAgICBWX3tpQn0gPSBcbXUgJismIFxiZXRhIHhfe2lCfVxcDQogICAgICAgICAgICAgIFxlbmR7YXJyYXl9ICANCiQkDQoNClRoZXNlIHV0aWxpdHkgZnVuY3Rpb25zIGFyZSB2ZXJ5IHNpbWlsYXIgdG8gdGhlIGZpcnN0IHNldCBvZiB1dGlsaXR5IGZ1bmN0aW9ucyB0aGF0IHdlIGRlZmluZWQgaW4gdGhlIHByZWNlZGluZyBzZWN0aW9uIGZvciB0aGUgY2FzZSBvZiBtb2RlIGNob2ljZS4NCg0KTmV4dCwgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gZm9yIHRoaXMgdG95IHNhbXBsZSBjYW4gYmUgd3JpdGVuIGFzIGEgZnVuY3Rpb24gb2YgJFxtdSQgYW5kICRcYmV0YSQuIEluIHRoaXMgd2F5LCBpdCBpcyBwb3NzaWJsZSB0byBjYWxjdWxhdGUgYW4gaW5pdGlhbCB2YWx1ZSBvZiB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBidSBzZXR0aW5nICRcbXUkIGFuZCAkXGJldGEkIHRvIHplcm8uIFdlIHdpbGwgY2FsbCB0aGlzICJFeHBlcmltZW50IDEiOg0KYGBge3J9DQptdSA8LSAwDQpiZXRhIDwtIDANCg0KUDFBXzEgPC0gKGV4cChiZXRhICogdHMkeGlBWzFdKS8oZXhwKGJldGEgKiB0cyR4aUFbMV0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsxXSkpKQ0KUDFCXzEgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbMV0pLyhleHAoYmV0YSAqIHRzJHhpQVsxXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzFdKSkpDQpQMkFfMSA8LSAoZXhwKGJldGEgKiB0cyR4aUFbMl0pLyhleHAoYmV0YSAqIHRzJHhpQVsyXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzJdKSkpDQpQMkJfMSA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsyXSkvKGV4cChiZXRhICogdHMkeGlBWzJdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbMl0pKSkNClAzQV8xIDwtIChleHAoYmV0YSAqIHRzJHhpQVszXSkvKGV4cChiZXRhICogdHMkeGlBWzNdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbM10pKSkNClAzQl8xIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzNdKS8oZXhwKGJldGEgKiB0cyR4aUFbM10pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlszXSkpKQ0KUDRBXzEgPC0gKGV4cChiZXRhICogdHMkeGlBWzRdKS8oZXhwKGJldGEgKiB0cyR4aUFbNF0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls0XSkpKQ0KUDRCXzEgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbNF0pLyhleHAoYmV0YSAqIHRzJHhpQVs0XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzRdKSkpDQpQNUFfMSA8LSAoZXhwKGJldGEgKiB0cyR4aUFbNV0pLyhleHAoYmV0YSAqIHRzJHhpQVs1XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzVdKSkpDQpQNUJfMSA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQls1XSkvKGV4cChiZXRhICogdHMkeGlBWzVdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNV0pKSkNClA2QV8xIDwtIChleHAoYmV0YSAqIHRzJHhpQVs2XSkvKGV4cChiZXRhICogdHMkeGlBWzZdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNl0pKSkNClA2Ql8xIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzZdKS8oZXhwKGJldGEgKiB0cyR4aUFbNl0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls2XSkpKQ0KICANCkwgPC0gIFAxQV8xXnRzJHlpQVsxXSAqIFAxQl8xXnRzJHlpQlsxXSAqIA0KICBQMkFfMV50cyR5aUFbMl0gKiBQMkJfMV50cyR5aUJbMl0gKiANCiAgUDNBXzFedHMkeWlBWzNdICogUDNCXzFedHMkeWlCWzNdICogDQogIFA0QV8xXnRzJHlpQVs0XSAqIFA0Ql8xXnRzJHlpQls0XSAqIA0KICBQNUFfMV50cyR5aUFbNV0gKiBQNUJfMV50cyR5aUJbNV0gKiANCiAgUDZBXzFedHMkeWlBWzZdICogUDZCXzFedHMkeWlCWzZdIA0KDQojIENyZWF0ZSBkYXRhIGZyYW1lIHRvIHRhYnVsYXRlIHJlc3VsdHM6DQpkZiA8LSBkYXRhLmZyYW1lKEluZGl2aWR1YWwgPSBjKDEsIDIsIDMsIDQsIDUsIDYpLA0KICAgICAgICAgICAgICAgICBDaG9pY2UgPSBjKCJBIiwgIkEiLCAiQiIsICJBIiwgIkIiLCAiQiIpLA0KICAgICAgICAgICAgICAgICBQQSA9IGMoUDFBXzEsIFAyQV8xLCBQM0FfMSwgUDRBXzEsIFA1QV8xLCBQNkFfMSksDQogICAgICAgICAgICAgICAgIFBCID0gYyhQMUJfMSwgUDJCXzEsIFAzQl8xLCBQNEJfMSwgUDVCXzEsIFA2Ql8xKSkNCg0Ka2FibGUoZGYsICJodG1sIiwgZGlnaXRzID0gNCwgYWxpZ24gPSAiYyIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKSAlPiUNCiAgZm9vdG5vdGUoZ2VuZXJhbCA9IHBhc3RlKCJUaGUgdmFsdWUgb2YgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gaXMgIiwgcm91bmQoTCwgZGlnaXRzID0gNCkpKQ0KYGBgDQoNCkFzIHlvdSBjYW4gc2VlLCB0aGF0IHRoZSBsb2dpdCBwcm9iYWJpbGl0aWVzIHdoZW4gYWxsIGNvZWZmaWNpZW50cyBhcmUgemVybyBpcyAkMC41JC4gQnkgc2V0dGluZyB0aGUgY29lZmZpY2llbnRzIHRvIHplcm8gd2UgaGF2ZSBkZWZpbmVkIHdoYXQgaXMgY2FsbGVkIGEgX251bGwgbW9kZWxfLiBTaW5jZSB0aGUgdmFyaWFibGVzIGFyZSBzZXQgdG8gemVybywgdGhpcyBtb2RlbCBoYXMgbm8gdXNlZnVsIGluZm9ybWF0aW9uIHRvIGVzdGltYXRlIHRoZSBwcm9iYWJpbGl0eSwgYW5kIHRoZXJlZm9yZSBpdCBhc3NpZ25zIGVxdWFsIHByb2JhYmlsaXRpZXMgdG8gYWxsIGFsdGVybmF0aXZlcy4gVGhlIHZhbHVlIG9mIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIGlzIGEgcmVsYXRpdmVseSBzbWFsbCAocG9zaXRpdmUpIG51bWJlciAocmVtZW1iZXIsIHRoZSBmdW5jdGlvbiBpcyBib3VuZGVkIGJldHdlZW4gemVybyBhbmQgb25lKS4NCg0KTm93LCB3ZSBjYW4gZXhwZXJpbWVudCB3aXRoIHRoZSBjb2VmZmljaWVudHMsIGJ5IGdpdmluZyB0aGVtIGRpZmZlcmVudCB2YWx1ZXMgYXMgZm9sbG93cyAoY2FsbCB0aGlzICJFeHBlcmltZW50IDIiKToNCmBgYHtyfQ0KbXUgPC0gMC41ICMgLTAuNQ0KYmV0YSA8LSAtMC41ICMgLTAuNQ0KDQpQMUFfMiA8LSAoZXhwKGJldGEgKiB0cyR4aUFbMV0pLyhleHAoYmV0YSAqIHRzJHhpQVsxXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzFdKSkpDQpQMUJfMiA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsxXSkvKGV4cChiZXRhICogdHMkeGlBWzFdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbMV0pKSkNClAyQV8yIDwtIChleHAoYmV0YSAqIHRzJHhpQVsyXSkvKGV4cChiZXRhICogdHMkeGlBWzJdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbMl0pKSkNClAyQl8yIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzJdKS8oZXhwKGJldGEgKiB0cyR4aUFbMl0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsyXSkpKQ0KUDNBXzIgPC0gKGV4cChiZXRhICogdHMkeGlBWzNdKS8oZXhwKGJldGEgKiB0cyR4aUFbM10pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlszXSkpKQ0KUDNCXzIgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbM10pLyhleHAoYmV0YSAqIHRzJHhpQVszXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzNdKSkpDQpQNEFfMiA8LSAoZXhwKGJldGEgKiB0cyR4aUFbNF0pLyhleHAoYmV0YSAqIHRzJHhpQVs0XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzRdKSkpDQpQNEJfMiA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQls0XSkvKGV4cChiZXRhICogdHMkeGlBWzRdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNF0pKSkNClA1QV8yIDwtIChleHAoYmV0YSAqIHRzJHhpQVs1XSkvKGV4cChiZXRhICogdHMkeGlBWzVdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNV0pKSkNClA1Ql8yIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzVdKS8oZXhwKGJldGEgKiB0cyR4aUFbNV0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls1XSkpKQ0KUDZBXzIgPC0gKGV4cChiZXRhICogdHMkeGlBWzZdKS8oZXhwKGJldGEgKiB0cyR4aUFbNl0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls2XSkpKQ0KUDZCXzIgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbNl0pLyhleHAoYmV0YSAqIHRzJHhpQVs2XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzZdKSkpDQogIA0KTCA8LSAgUDFBXzJedHMkeWlBWzFdICogUDFCXzJedHMkeWlCWzFdICogDQogIFAyQV8yXnRzJHlpQVsyXSAqIFAyQl8yXnRzJHlpQlsyXSAqIA0KICBQM0FfMl50cyR5aUFbM10gKiBQM0JfMl50cyR5aUJbM10gKiANCiAgUDRBXzJedHMkeWlBWzRdICogUDRCXzJedHMkeWlCWzRdICogDQogIFA1QV8yXnRzJHlpQVs1XSAqIFA1Ql8yXnRzJHlpQls1XSAqIA0KICBQNkFfMl50cyR5aUFbNl0gKiBQNkJfMl50cyR5aUJbNl0gDQoNCiMgQ3JlYXRlIGRhdGEgZnJhbWUgdG8gdGFidWxhdGUgcmVzdWx0czoNCmRmIDwtIGRhdGEuZnJhbWUoSW5kaXZpZHVhbCA9IGMoMSwgMiwgMywgNCwgNSwgNiksDQogICAgICAgICAgICAgICAgIENob2ljZSA9IGMoIkEiLCAiQSIsICJCIiwgIkEiLCAiQiIsICJCIiksDQogICAgICAgICAgICAgICAgIFBBID0gYyhQMUFfMiwgUDJBXzIsIFAzQV8yLCBQNEFfMiwgUDVBXzIsIFA2QV8yKSwNCiAgICAgICAgICAgICAgICAgUEIgPSBjKFAxQl8yLCBQMkJfMiwgUDNCXzIsIFA0Ql8yLCBQNUJfMiwgUDZCXzIpKQ0KDQprYWJsZShkZiwgImh0bWwiLCBkaWdpdHMgPSA0LCBhbGlnbiA9ICJjIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICBmb290bm90ZShnZW5lcmFsID0gcGFzdGUoIlRoZSB2YWx1ZSBvZiB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBpcyAiLCByb3VuZChMLCBkaWdpdHMgPSA0KSkpDQpgYGANCg0KTm90aWNlIGhvdyBjaGFuZ2luZyB0aGUgY29lZmZpY2llbnRzIGhhcyB0d28gZWZmZWN0cywgYXMgeW91IHdvdWxkIGV4cGVjdDogdGhlIHByb2JhYmlsaXRpZXMgY2hhbmdlIGFuZCB0aGUgdmFsdWUgb2YgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gY2hhbmdlcyB0b28uIEluc3BlY3QgdGhlIHByb2JhYmlsaXRpZXMgYW5kIHRoZSB2YWx1ZSBvZiB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiB3aXRoIHRoZSBuZXcgY29lZmZpY2llbnRzLiBXaGF0IGRvIHlvdSBub3RpY2U/DQoNCklmIHlvdSBhcmUgd29ya2luZyB3aXRoIHRoZSBSIE5vdGVib29rLCBhdCB0aGlzIHBvaW50IHlvdSBjYW4gdHJ5IGNoYW5naW5nIHRoZSBjb2VmZmljaWVudHMuIENhbiB5b3UgaW1wcm92ZSB0aGUgdmFsdWUgb2YgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24sIG9yIG1heWJlIGV2ZW4gbWFrZSBpdCB3b3JzZT8NCg0KVGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gY2FuIGJlIHBsb3R0ZWQgYXMgc2hvd24gYmVsb3cuIElmIHlvdSBob3ZlciBvdmVyIHRoZSBwbG90LCB5b3UgY2FuIHNlZSBob3cgdGhlIHZhbHVlIG9mIHRoZSBsaWtlbGlob29kIGNoYW5nZXMgYXMgYSBmdW5jdGlvbiBvZiAkXG11JCBhbmQgJFxiZXRhJDoNCmBgYHtyIGZpZy1saWtlbGlob29kLWZ1bmN0aW9uLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSAiXFxsYWJlbHtmaWc6ZmlnLWxpa2VsaWhvb2QtZnVuY3Rpb259TGlrZWxpaG9vZCBmdW5jdGlvbiBmb3IgdG95IGRhdGFzZXQifQ0KIyBDcmVhdGUgYSBncmlkIHRvIHBsb3QgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24NCm11ID0gc2VxKGZyb20gPSAtMSwgdG8gPSAxLCBieSA9IDAuMDUpDQpiZXRhID0gc2VxKGZyb20gPSAtMiwgdG8gPSAwLCBieSA9IDAuMDUpDQpjb2VmZnMgPC0gZXhwYW5kLmdyaWQobXUsIGJldGEpDQoNCiMgRGVmaW5lIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uDQpsa2ggPC0gZnVuY3Rpb24obXUgPSAwLCBiZXRhID0gMCl7DQogIHRzIDwtIGRhdGEuZnJhbWUoSW5kaXZpZHVhbCA9IGMoMSwgMiwgMywgNCwgNSwgNiksDQogICAgICAgICAgICAgICAgICAgICAgICAgQ2hvaWNlID0gYygiQSIsICJBIiwgIkIiLCAiQSIsICJCIiwgIkIiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeWlBID0gYygxLCAxLCAwLCAxLCAwLCAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB5aUIgPSBjKDAsIDAsIDEsIDAsIDEsIDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHhpQSA9IGMoNSwgMiwgNSwgMSwgNCwgMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgeGlCID0gYyg0LCA1LCAyLCA2LCAxLCA0KSkNCiAgDQogIFAxQSA8LSAoZXhwKGJldGEgKiB0cyR4aUFbMV0pLyhleHAoYmV0YSAqIHRzJHhpQVsxXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzFdKSkpDQogIFAxQiA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsxXSkvKGV4cChiZXRhICogdHMkeGlBWzFdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbMV0pKSkNCiAgUDJBIDwtIChleHAoYmV0YSAqIHRzJHhpQVsyXSkvKGV4cChiZXRhICogdHMkeGlBWzJdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbMl0pKSkNCiAgUDJCIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzJdKS8oZXhwKGJldGEgKiB0cyR4aUFbMl0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsyXSkpKQ0KICBQM0EgPC0gKGV4cChiZXRhICogdHMkeGlBWzNdKS8oZXhwKGJldGEgKiB0cyR4aUFbM10pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlszXSkpKQ0KICBQM0IgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbM10pLyhleHAoYmV0YSAqIHRzJHhpQVszXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzNdKSkpDQogIFA0QSA8LSAoZXhwKGJldGEgKiB0cyR4aUFbNF0pLyhleHAoYmV0YSAqIHRzJHhpQVs0XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzRdKSkpDQogIFA0QiA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQls0XSkvKGV4cChiZXRhICogdHMkeGlBWzRdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNF0pKSkNCiAgUDVBIDwtIChleHAoYmV0YSAqIHRzJHhpQVs1XSkvKGV4cChiZXRhICogdHMkeGlBWzVdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNV0pKSkNCiAgUDVCIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzVdKS8oZXhwKGJldGEgKiB0cyR4aUFbNV0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls1XSkpKQ0KICBQNkEgPC0gKGV4cChiZXRhICogdHMkeGlBWzZdKS8oZXhwKGJldGEgKiB0cyR4aUFbNl0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls2XSkpKQ0KICBQNkIgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbNl0pLyhleHAoYmV0YSAqIHRzJHhpQVs2XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzZdKSkpDQogIA0KICBQMUFedHMkeWlBWzFdICogUDFCXnRzJHlpQlsxXSAqIA0KICBQMkFedHMkeWlBWzJdICogUDJCXnRzJHlpQlsyXSAqIA0KICBQM0FedHMkeWlBWzNdICogUDNCXnRzJHlpQlszXSAqIA0KICBQNEFedHMkeWlBWzRdICogUDRCXnRzJHlpQls0XSAqIA0KICBQNUFedHMkeWlBWzVdICogUDVCXnRzJHlpQls1XSAqIA0KICBQNkFedHMkeWlBWzZdICogUDZCXnRzJHlpQls2XSANCn0NCg0KIyBFdmFsdWF0ZSB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBvbiB0aGUgZ3JpZA0KTCA8LSBsa2gobXUgPSBjb2VmZnMkVmFyMSwgYmV0YSA9IGNvZWZmcyRWYXIyKQ0KDQpMIDwtIGRhdGEuZnJhbWUobXUgPSBjb2VmZnMkVmFyMSwgYmV0YSA9IGNvZWZmcyRWYXIyLCBMKQ0KTCA8LSB4dGFicyhMIH4gYmV0YSArIG11LCBMKQ0KDQpwbG90X2x5KHogPSB+TCwgeCA9IH5tdSwgeSA9IH5iZXRhKSAlPiUgDQogIGFkZF9zdXJmYWNlKCkgJT4lDQogIGxheW91dChzY2VuZSA9IGxpc3QoDQogICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAieC1heGlzIChtdSkiKSwNCiAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJ5LWF4aXMgKGJldGEpIiksDQogICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiei1heGlzIChMKSIpDQogICAgKSkNCg0KYGBgDQoNCkZyb20gRmlndXJlIFxAcmVmKGZpZzpmaWctZXZpLWRpc3RyaWJ1dGlvbikgd2UgY2FuIHNlZSB0aGF0IHRoZSBhcHByb3hpbWF0ZSB2YWx1ZXMgb2YgdGhlIGNvZWZmaWNpZW50cyB0aGF0IG1heGltaXplIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIGFyZSAkXG11PTAuMTAkIGFuZCAkXGJldGE9LTAuNjUkLiBJZiB3ZSB1c2UgdGhlc2UgY29lZmZpY2llbnRzIHRvIGNhbGN1bGF0ZSB0aGUgbG9naXQgcHJvYmFiaWxpdGllcywgd2UgY2FuIGNvbXBhcmUgdG8gdGhlIHByb2JhYmlsaXRpZXMgb2YgRXhwZXJpbWVudHMgMSBhbmQgMjoNCmBgYHtyfQ0KIyBBcHByb3hpbWF0ZSB2YWx1ZXMgdGhhdCBtYXhpbWl6ZSB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbi4NCm11IDwtIDAuMTANCmJldGEgPC0gLTAuNjUNCg0KUDFBXzMgPC0gKGV4cChiZXRhICogdHMkeGlBWzFdKS8oZXhwKGJldGEgKiB0cyR4aUFbMV0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsxXSkpKQ0KUDFCXzMgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbMV0pLyhleHAoYmV0YSAqIHRzJHhpQVsxXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzFdKSkpDQpQMkFfMyA8LSAoZXhwKGJldGEgKiB0cyR4aUFbMl0pLyhleHAoYmV0YSAqIHRzJHhpQVsyXSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzJdKSkpDQpQMkJfMyA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQlsyXSkvKGV4cChiZXRhICogdHMkeGlBWzJdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbMl0pKSkNClAzQV8zIDwtIChleHAoYmV0YSAqIHRzJHhpQVszXSkvKGV4cChiZXRhICogdHMkeGlBWzNdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbM10pKSkNClAzQl8zIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzNdKS8oZXhwKGJldGEgKiB0cyR4aUFbM10pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQlszXSkpKQ0KUDRBXzMgPC0gKGV4cChiZXRhICogdHMkeGlBWzRdKS8oZXhwKGJldGEgKiB0cyR4aUFbNF0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls0XSkpKQ0KUDRCXzMgPC0gKGV4cChtdSArIGJldGEgKiB0cyR4aUJbNF0pLyhleHAoYmV0YSAqIHRzJHhpQVs0XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzRdKSkpDQpQNUFfMyA8LSAoZXhwKGJldGEgKiB0cyR4aUFbNV0pLyhleHAoYmV0YSAqIHRzJHhpQVs1XSkgKyBleHAobXUgKyBiZXRhICogdHMkeGlCWzVdKSkpDQpQNUJfMyA8LSAoZXhwKG11ICsgYmV0YSAqIHRzJHhpQls1XSkvKGV4cChiZXRhICogdHMkeGlBWzVdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNV0pKSkNClA2QV8zIDwtIChleHAoYmV0YSAqIHRzJHhpQVs2XSkvKGV4cChiZXRhICogdHMkeGlBWzZdKSArIGV4cChtdSArIGJldGEgKiB0cyR4aUJbNl0pKSkNClA2Ql8zIDwtIChleHAobXUgKyBiZXRhICogdHMkeGlCWzZdKS8oZXhwKGJldGEgKiB0cyR4aUFbNl0pICsgZXhwKG11ICsgYmV0YSAqIHRzJHhpQls2XSkpKQ0KICANCkwgPC0gIFAxQV8zXnRzJHlpQVsxXSAqIFAxQl8zXnRzJHlpQlsxXSAqIA0KICBQMkFfM150cyR5aUFbMl0gKiBQMkJfM150cyR5aUJbMl0gKiANCiAgUDNBXzNedHMkeWlBWzNdICogUDNCXzNedHMkeWlCWzNdICogDQogIFA0QV8zXnRzJHlpQVs0XSAqIFA0Ql8zXnRzJHlpQls0XSAqIA0KICBQNUFfM150cyR5aUFbNV0gKiBQNUJfM150cyR5aUJbNV0gKiANCiAgUDZBXzNedHMkeWlBWzZdICogUDZCXzNedHMkeWlCWzZdIA0KDQojIENyZWF0ZSBkYXRhIGZyYW1lIHRvIHRhYnVsYXRlIHJlc3VsdHM6DQpkZiA8LSBkYXRhLmZyYW1lKEluZGl2aWR1YWwgPSBjKDEsIDIsIDMsIDQsIDUsIDYpLA0KICAgICAgICAgICAgICAgICBDaG9pY2UgPSBjKCJBIiwgIkEiLCAiQiIsICJBIiwgIkIiLCAiQiIpLA0KICAgICAgICAgICAgICAgICBQQV8xID0gYyhQMUFfMSwgUDJBXzEsIFAzQV8xLCBQNEFfMSwgUDVBXzEsIFA2QV8xKSwNCiAgICAgICAgICAgICAgICAgUEJfMSA9IGMoUDFCXzEsIFAyQl8xLCBQM0JfMSwgUDRCXzEsIFA1Ql8xLCBQNkJfMSksDQogICAgICAgICAgICAgICAgIFBBXzEgPSBjKFAxQV8yLCBQMkFfMiwgUDNBXzIsIFA0QV8yLCBQNUFfMiwgUDZBXzIpLA0KICAgICAgICAgICAgICAgICBQQl8xID0gYyhQMUJfMiwgUDJCXzIsIFAzQl8yLCBQNEJfMiwgUDVCXzIsIFA2Ql8yKSwNCiAgICAgICAgICAgICAgICAgUEFfMSA9IGMoUDFBXzMsIFAyQV8zLCBQM0FfMywgUDRBXzMsIFA1QV8zLCBQNkFfMyksDQogICAgICAgICAgICAgICAgIFBCXzEgPSBjKFAxQl8zLCBQMkJfMywgUDNCXzMsIFA0Ql8zLCBQNUJfMywgUDZCXzMpKQ0KDQprYWJsZShkZiwgImh0bWwiLCBkaWdpdHMgPSA0LCANCiAgICAgIGNvbC5uYW1lcyA9IGMoIkluZGl2aWR1YWwiLCAiQ2hvaWNlIiwgIlBBIiwgIlBCIiwgIlBBIiwgIlBCIiwgIlBBIiwgIlBCIiksDQogICAgICBhbGlnbiA9ICJjIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIiAiID0gMSwgIkV4cGVyaW1lbnQgMSIgPSAyLCAiRXhwZXJpbWVudCAyIiA9IDIsICJBcHByb3ggTWF4IExpa2VsaWhvb2QiID0gMikpDQpgYGANCg0KTWF4aW1pemluZyB0aGUgbGlrZWxpaG9vZCBpcyBhIHVzZWZ1bCBjcml0ZXJpb24gdG8gZXN0aW1hdGUgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgbW9kZWxzLCBzaW5jZSB0aGlzIGNyaXRlcmlvbiBwcm92aWRlcyB0aGUgb3B0aW1hbCBwcm9iYWJpbGl0aWVzIG9mIHRoZSByaWdodCBhbHRlcm5hdGl2ZSBiZWluZyBjaG9zZW4uIE1pbmQgeW91LCB0aGlzIGRvZXMgbm90IG5lY2Vzc2FyaWx5IG1lYW4gdGhhdCB0aG9zZSBwcm9iYWJpbGl0aWVzIHdpbGwgYmUgaGlnaCAtIGhvd2V2ZXIsIHdlIGNhbiBiZSBjZXJ0YWluIHRoYXQgdGhleSB3aWxsIGJlIHRoZSBiZXN0IGZvciB0aGUgbW9kZWwgdW5kZXIgY29uc2lkZXJhdGlvbiBmb3IgdGhlIHNhbXBsZSBnaXZlbi4NCg0KSW4gdGhpcyB0b3kgZXhhbXBsZSB3ZSAic29sdmVkIiB0aGUgcHJvYmxlbSBvZiBtYXhpbWl6aW5nIHRoZSBsaWtlbGlob29kIGJ5IGhhbmQuIFRoaXMgaXMgcmF0aGVyIGRpZmZpY3VsdCwgdW5mZWFzaWJsZSBldmVuLCBpbiBtb3N0IGFwcGxpZWQgc2l0dWF0aW9ucyB3aXRoIGxhcmdlIHNhbXBsZXMgYW5kL29yIG1vcmUgdGhhbiBvbmUgdmFyaWFibGUuIEZvcnR1bmF0ZWx5LCB0aGVyZSBhcmUgYSBudW1iZXIgb2YgbnVtZXJpY2FsIGFsZ29yaXRobXMgdGhhdCBjYW4gYmUgdXNlZCB0byBtYXhpbWl6ZSB0aGUgbGlrZWxpaG9vZC4gV2Ugd2lsbCBub3QgZGlzY3VzcyB0aGlzIGluIGRldGFpbCwgYnV0IGludGVyZXN0ZWQgcmVhZGVycyBjYW4gY29uc3VsdCBUcmFpbiBbLUBUcmFpbjIwMDlkaXNjcmV0ZTsgU2VjdGlvbiAzLjddIGZvciBkZXRhaWxzLiBUaGUgYG1sb2dpdGAgcGFja2FnZSBpbXBvcnRzIHRoZSBwYWNrYWdlIGBtYXhMaWtgIFtASGVubmluZ3NlbjIwMTFtYXhsaWtdLCB3aGljaCBpbXBsZW1lbnRzIGNhbm9uaWNhbCBhbGdvcml0aG1zIGluY2x1ZGluZyBbTmV3dG9uLVJhcGhzb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05ld3RvbiUyN3NfbWV0aG9kKSwgdGhlIEJlcm5kdOKAk0hhbGzigJNIYWxs4oCTSGF1c21hbiAob3IgW0JISEhdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Jlcm5kdC1IYWxsLUhhbGwtSGF1c21hbl9hbGdvcml0aG0pKSwgYW5kIHRoZSBCcm95ZGVu4oCTRmxldGNoZXLigJNHb2xkZmFyYuKAk1NoYW5ubyAob3IgW0JGR1NdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Jyb3lkZW4tRmxldGNoZXItR29sZGZhcmItU2hhbm5vX2FsZ29yaXRobSkpIGFsZ29yaXRobS4NCg0KDQpJbiBwcmFjdGljZSwgdGhlIGFsZ29yaXRobXMgYWJvdmUgbWF4aW1pemUgbm90IHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uLCBidXQgYSB0cmFuc2Zvcm1hdGlvbiB0aGVyZW9mLCBjYWxsZWQgdGhlIF9sb2ctbGlrZWxpaG9vZF8sIHdoaWNoIGlzIG9idGFpbmVkIGJ5IHRha2luZyB0aGUgbmF0dXJhbCBsb2dhcml0aG0gb2YgdGhlIGZ1bmN0aW9uLCB0byBnaXZlOg0KJCQNCmwgPSBcc3VtX3tpPW59Xk5cc3VtX3tqPTF9XkogeV97aWp9bG9nKFBfe2lqfSkNCiQkDQpTaW5jZSB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBpcyBib3VuZCBiZXR3ZWVuIHplcm8gYW5kIG9uZSwgdGhlIGxvZy1saWtlbGlob29kIGlzIGJvdW5kIGJldHdlZW4gbWludXMgaW5maW5pdHkgYW5kIHplcm8uIFRoZSB2YWx1ZSBvZiB0aGUgbWF4aW1pemVkIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIHByb3ZpZGVzIGEgdXNlZnVsIGRpYWdub3N0aWMgdG8gY29tcGFyZSBtb2RlbHMsIHNpbmNlIGhpZ2hlciB2YWx1ZXMgYXJlIGluZGljYXRpdmUgb2YgYSBiZXR0ZXIgbW9kZWwuIFNldmVyYWwgc3RhdGlzdGljYWwgdGVzdHMgKHN1Y2ggYXMgdGhlIGxpa2VsaWhvb2QgcmF0aW8pIGNhbiBiZSB1c2VkIHRvIHRlc3QgdGhlIGh5cG90aGVzaXMgdGhhdCBhIG1vZGVsIGlzIGEgc2lnbmlmaWNhbnQgaW1wcm92ZW1lbnQgb3ZlciBvdGhlciwgYW5kIGFyZSB0aHVzIHVzZWZ1bCBmb3IgbW9kZWwgc2VsZWN0aW9uIHB1cnBvc2VzLiBIb3dldmVyLCBiZWZvcmUgZGlzY3Vzc2luZyBtb2RlbCBkaWFnbm9zdGljcywgd2Ugd2lsbCBzZWUgaG93IG11bHRpbm9taWFsIGxvZ2l0IG1vZGVscyBhcmUgZXN0aW1hdGVkIHVzaW5nIGBtbG9naXRgLg0KDQojIyBFeGFtcGxlOiBBIGxvZ2l0IG1vZGVsIG9mIG1vZGUgY2hvaWNlDQoNCkNvbWluZyBiYWNrIHRvIHRoZSB0cmFuc3BvcnRhdGlvbiBtb2RlIGNob2ljZSBkYXRhc2V0LCB3ZSBoYWQgYWxyZWFkeSBkZWZpbmVkIHNvbWUgZm9ybXVsYXMgKGkuZS4sIHV0aWxpdHkgZnVuY3Rpb25zKSB0aGF0IHdlIGNhbiB1c2UgdG8gZXN0aW1hdGUgYSBtb2RlbC4NCg0KVGhlIGZ1bmN0aW9uIHRvIGVzdGltYXRlIGEgbW9kZWwgaXMgYG1sb2dpdCgpYC4gVGhpcyBmdW5jdGlvbiByZXF1aXJlcyBhdCBsZWFzdCB0d28gYXJndW1lbnRzOiBhbiBgbUZvcm11bGFgIG9iamVjdCBhbmQgYSBkYXRhc2V0LiBXZSBjYW4gdmVyaWZ5IHRoYXQgdGhlIGZvcm11bGFzIHdlIGNyZWF0ZWQgYWJvdmUgYXJlIG9mIHRoaXMgY2xhc3M6DQpgYGB7cn0NCmNsYXNzKGYxKQ0KY2xhc3MoZjIpDQpjbGFzcyhmMykNCmBgYA0KDQpUaGUgdmFsdWUgKG91dHB1dCkgb2YgdGhlIGZ1bmN0aW9uIGNhbiBiZSBuYW1lZCBhbmQgc2F2ZWQgdG8gYW4gb2JqZWN0IGZvciBmdXJ0aGVyIGFuYWx5c2lzIG9yIGZvciBmdXJ0aGVyIHByb2Nlc3NpbmcsIHBvc3QtZXN0aW1hdGlvbi4gQmVnaW4gYnkgZXN0aW1hdGluZyBhIG1vZGVsIHVzaW5nIHRoZSBzaW1wbGVzdCBvZiBvdXIgZm9ybXVsYXM6DQpgYGB7cn0NCm1vZGVsMSA8LSBtbG9naXQoZjEsIG1jX2NvbW11dGUpDQpzdW1tYXJ5KG1vZGVsMSkNCmBgYA0KDQpUaGUgb3V0cHV0IG9mIHRoZSBmdW5jdGlvbiBpbmNsdWRlcyB0aGUgZXN0aW1hdGVkIGZyZXF1ZW5jaWVzIG9mIGFsdGVybmF0aXZlcyBpbiBhZGRpdGlvbiB0byBpbmZvcm1hdGlvbiBhYm91dCB0aGUgb3B0aW1pemF0aW9uIHByb2NlZHVyZS4gRm9yIGluc3RhbmNlLCB0aGUgbWVzc2FnZSAic3VjY2Vzc2l2ZSBmdW5jdGlvbiB2YWx1ZXMgd2l0aGluIHRvbGVyYW5jZSBsaW1pdHMiIGluZGljYXRlcyB0aGF0IHRoZSBhbGdvcml0aG0gY29udmVyZ2VkIG5vcm1hbGx5LiANCg0KVGhlIG91dHB1dCBhbHNvIHJlcG9ydHMgdGhlIGVzdGltYXRlZCB2YWx1ZXMgb2YgdGhlIGNvZWZmaWNpZW50cywgYWxvbmcgd2l0aCBzdGFuZGFyZCBlcnJvcnMsIHotdmFsdWVzLCBhbmQgcC12YWx1ZXMuIFRoZSBudWxsIGh5cG90aGVzaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBjb2VmZmljaWVudHMgaXMgdGhhdCB0aGV5IGFyZSB6ZXJvLiBBbiBhbmFseXN0IGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBhbnkgY2FzZSwgYnV0IHNtYWxsIHAtdmFsdWVzIGluZGljYXRlIGEgbG93IHByb2JhYmlsaXR5IHRoYXQgdGhlIGNvZWZmaWNpZW50IGlzIHplcm8gLSBhbmQgdGhlcmVmb3JlIGluY3JlYXNlIHRoZSBjb25maWRlbmNlIHRoYXQgYnkgcmVqZWN0aW5nIHRoZSBudWxsIHRoZSBhbmFseXN0IGlzIG5vdCBtaXN0YWtlbmx5IHJlamVjdGluZyBhIHRydWUgemVyby4gSW4gdGhlIHByZXNlbnQgY2FzZSwgd2l0aCBwLXZhbHVlcyBzbWFsbGVyIHRoYW4gMC4wMDAxLCB0aGUgbnVsbCBoeXBvdGhlc2lzIGNhbiBiZSBjb21mb3J0YWJseSByZWplY3RlZCBmb3IgZXZlcnkgY29lZmZpY2llbnQuIFRoZSBzbWFsbCBwLXZhbHVlcyBtZWFuIHRoYXQgaXQgaXMgaGlnaGx5IHVubGlrZWx5IHRoYXQgdGhlIGNvZWZmaWNpZW50cyBhcmUgemVyby4NCg0KVGhpcyBzaW1wbGUgbW9kZWwgaW5jbHVkZXMgdGhyZWUgYWx0ZXJuYXRpdmUtc3BlY2lmaWMgY29uc3RhbnRzIGFuZCBvbmUgYWx0ZXJuYXRpdmUtc3BlY2lmaWMgdmFyaWFibGUgd2l0aCBhIGdlbmVyaWMgY29lZmZpY2llbnQuIFRoZSBzaWducyBvZiB0aGUgY29lZmZpY2llbnRzIGFyZSBpbmZvcm1hdGl2ZS4gU2luY2UgdGhlIHJlZmVyZW5jZSBtb2RlIGlzICJDeWNsZSIsIHRoZSBwb3NpdGl2ZSB2YWx1ZXMgb2YgdGhlIGNvbnN0YW50cyBpbmRpY2F0ZSB0aGF0LCBvdGhlciB0aGluZ3MgYmVpbmcgZXF1YWwsIGN5Y2xpbmcgaXMgdGhlIGxlYXN0IHByZWZlcnJlZCBtb2RlLCBmb2xsb3dlZCBieSBIU1IgYW5kIHRoZW4gQ2FyLiBUaGUgbW9zdCBwcmVmZXJyZWQgbW9kZSAoYWdhaW4sIG90aGVyIHRoaW5ncyBiZWluZyBlcXVhbCksIGlzIFdhbGsuIFRoaXMgaXMgdmVyaWZpZWQgZnJvbSB0aGUgZXN0aW1hdGVkIGZyZXF1ZW5jaWVzIG9mIHRoZSBtb2Rlcy4NCg0KVGhlIG5lZ2F0aXZlIGNvZWZmaWNpZW50IGZvciB0aW1lIGluZGljYXRlcyB0aGF0IHRpbWUgaXMgYSAiY29zdCIsIGluIG90aGVyIHdvcmRzLCB0aGUgdXRpbGl0eSBvZiB0cmF2ZWxsaW5nIHRlbmRzIHRvIGRlY2xpbmUgd2l0aCBpbmNyZWFzaW5nIHRyYXZlbCB0aW1lcy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBzbG93ZXIgbW9kZXMgd2lsbCB0ZW5kIHRvIGhhdmUgbG93ZXIgdXRpbGl0aWVzLg0KDQpGaW5hbGx5LCB0aGUgbWF4aW1pemVkIHZhbHVlIG9mIHRoZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiBpcyByZXBvcnRlZCwgYWxvbmcgd2l0aCB0d28gZGlhZ25vc3RpY3MsIE1jRmFkZGVuIFJeMiAoaW4gcmVhbGl0eSAkXHJob14yJCkgYW5kIGEgbGlrZWxpaG9vZCByYXRpbyB0ZXN0LiBXZSB3aWxsIGNvbWUgYmFjayB0byB0aGVzZSBkaWFnbm9zdGljcyBiZWxvdywgYnV0IGZpcnN0LCB3ZSB3aWxsIGVzdGltYXRlIGEgbmV3IG1vZGVsIHVzaW5nIHRoZSBzZWNvbmQgZm9ybXVsYS4NCmBgYHtyfQ0KbW9kZWwyIDwtIG1sb2dpdChmMiwgbWNfY29tbXV0ZSkNCnN1bW1hcnkobW9kZWwyKQ0KYGBgDQoNCk5vdyB0aGVyZSBpcyBhbiBpbmRpdmlkdWFsLXNwZWNpZmljIHZhcmlhYmxlIGluIHRoZSBtb2RlbCAoaS5lLiwgYWdlKS4gT25seSBvbmUgb2YgdGhvc2UgY29lZmZpY2llbnRzIGlzIHNpZ25pZmljYW50IGF0IGNvbnZlbnRpb25hbCBsZXZlbHMgKGkuZS4sICRwPDAuMDUkKSwgYW5kIGl0IGlzIG5lZ2F0aXZlLiBTaW5jZSB0aGUgcmVmZXJlbmNlIGlzICJDeWNsZSIsIGEgbmVnYXRpdmUgdmFsdWUgaW5kaWNhdGVzIHRoYXQgdGhlIHV0aWxpdHkgb2Ygd2Fsa2luZyBkZWNsaW5lcyB3aXRoIGFnZSB3aXRoIHJlc3BlY3QgdG8gdGhlIHV0aWxpdHkgb2YgY3ljbGluZy4gVHdvIG90aGVyIGNvZWZmaWNpZW50cyBmb3IgYWdlIChpbiB0aGUgdXRpbGl0eSBvZiBIU1IgYW5kIENBUikgYXJlIG5vdCBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHplcm8sIG1lYW5pbmcgdGhhdCBhZ2UgZG9lcyBub3Qgc2lnbmlmaWNhbnRseSBjaGFuZ2UgdGhlIHV0aWxpdHkgb2YgdHJhdmVsIGJ5IEhTUiBhbmQgQ2FyIHdpdGggcmVzcGVjdCB0byBDeWNsZS4NCg0KTm90ZSB0aGF0IGl0IGlzIHBvc3NpYmxlIHRvIHNlbGVjdCB0aGUgcmVmZXJlbmNlIGxldmVsIGZvciB0aGUgdXRpbGl0aWVzIHdoZW4gZXN0aW1hdGluZyB0aGUgbW9kZWwuIEZvciBleGFtcGxlLCBsZXRzIHJlZXN0aW1hdGUgdGhlIG1vZGVsIGFib3ZlLCBidXQgbm93IHVzaW5nIHRoZSB1dGlsaXR5IG9mIFdhbGsgYXMgdGhlIHJlZmVyZW5jZToNCmBgYHtyfQ0KbW9kZWwyIDwtIG1sb2dpdChmMiwgbWNfY29tbXV0ZSwgcmVmbGV2ZWwgPSAiV2FsayIpDQpzdW1tYXJ5KG1vZGVsMikNCmBgYA0KDQpOb3cgYWxsIGFnZS1yZWxhdGVkIGNvZWZmaWNpZW50cyBhcmUgc2lnbmlmaWNhbnQhIFdoZXJlYXMgc29tZSBvZiB0aGVtIGFyZSBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgd2l0aCByZXNwZWN0IHRvIGVhY2ggb3RoZXIgYXMgc2VlbiBhYm92ZSAoZS5nLiBDeWNsZSBhbmQgSFNSKSwgdGhlIGFyZSBfYWxsXyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHRoZSByZWZlcmVuY2UuIFNpbmNlIHRoZSBjb2VmZmljaWVudHMgYXJlIHBvc2l0aXZlLCB0aGlzIGluZGljYXRlcyB0aGF0IHRoZSB1dGlsaXRpZXMgb2YgY3ljbGluZywgdXNpbmcgSFNSLCBhbmQgdHJhdmVsaW5nIGJ5IGNhciBhbGwgaW5jcmVhc2Ugd2l0aCBhZ2UgX3dpdGggcmVzcGVjdCB0byB3YWxraW5nXy4NCg0KVGhlIHZhbHVlIG9mIHRoZSBtYXhpbWl6ZWQgbG9nLWxpa2VsaWhvb2QgYW5kIG90aGVyIGRpYWdub3N0aWNzIGFyZSBpZGVudGljYWwsIGlycmVzcGVjdGl2ZSBvZiB3aGljaCBtb2RlIGlzIHNlbGVjdGVkIGFzIGEgdXRpbGl0eS4gSW4gZXNzZW5jZSwgdGhlIG1vZGVscyBhcmUgdGhlIHNhbWUsIGJ1dCB0aGV5IHByb3ZpZGUgYSBkaWZmZXJlbnQgcGVyc3BlY3RpdmUgb24gaG93IHNvbWUgY29lZmZpY2llbnRzIHJlbGF0ZSB0byBlYWNoIG90aGVyIGFjcm9zcyBhbHRlcm5hdGl2ZXMuDQoNCldlIGNhbiB2aXN1YWxseSBleHBsb3JlIGhvdyB0aGUgcHJvYmFiaWxpdHkgb2YgY2hvb3NpbmcgZGlmZmVyZW50IG1vZGVzIHZhcmllcyB3aXRoIGFnZS4gRmlyc3Qgc3VtbWFyaXplIHRoZSBhZ2UgdmFyaWFibGU6DQpgYGB7cn0NCnN1bW1hcnkobWNfY29tbXV0ZSRhZ2UpDQpgYGANCg0KQ29weSB0aGUgZGF0YWZyYW1lIHVzZWQgdG8gZXN0aW1hdGUgdGhlIG1vZGVsLCBidXQgb25seSBlbm91Z2ggY29sdW1ucyB0byBleHBsb3JlIGFuIGFnZSByYW5nZSBvZiAxMCB5ZWFycywgc2F5IGZyb20gMTcgdG8gMjYuIFNpbmNlIHRoZXJlIGFyZSBmb3VyIGFsdGVybmF0aXZlcywgdGhpcyBtZWFucyB0aGF0IHdlIG5lZWQgZm91cnR5IHJvd3MgKCRKID0gNCQgYW5kIHRlbiBvbmUteWVhciBpbnRlcnZhbHMpOg0KYGBge3J9DQptY19jb21tdXRlX3ByZWRpY3QgPC0gbWNfY29tbXV0ZVsxOjQwLF0NCmBgYA0KDQpSZXBsYWNlIHRoZSBhZ2UgdmFyaWFibGUgdXNpbmcgdmFsdWVzIGZvciBhZ2VzIDE3IHRvIDI2Og0KYGBge3J9DQptY19jb21tdXRlX3ByZWRpY3QkYWdlIDwtIHJlcChjKDE3OjI2KSwgZWFjaCA9IDQpDQpgYGANCg0KUmVwbGFjZSB0aW1lIGJ5IG1lZGlhbiB0cmF2ZWwgdGltZToNCmBgYHtyfQ0KbWNfY29tbXV0ZV9wcmVkaWN0JHRpbWUgPC0gbWVkaWFuKG1jX2NvbW11dGUkdGltZSkNCmBgYA0KDQpOZXh0LCBwcmVkaWN0IHRoZSBwcm9iYWJpbGl0aWVzIHVzaW5nIHRoZSBgcHJlZGljdCgpYCBmdW5jdGlvbjoNCmBgYHtyfQ0KcHJvYnMgPC0gcHJlZGljdChtb2RlbDIsIG5ld2RhdGEgPSBtY19jb21tdXRlX3ByZWRpY3QpDQpgYGANCg0KVGhlIHZhbHVlIChvdXRwdXQpIG9mIGBwcmVkaWN0YCBpcyBhIDEwLWJ5LTQgbWF0cml4IHRoYXQgY29udGFpbnMgdGhlIHByb2JhYmlsaXR5IGZvciB0ZW4gYWdlIHZhbHVlcyAoaS5lLiwgMTYsIDE3LCAxOCwgLi4uLCAyNiksIGFuZCBmb3VyIG1vZGVzIChXYWxrLCBDeWNsZSwgSFNSLCBDYXIpLiBUbyBmYWNpbGl0YXRlIHBsb3R0aW5nLCB3ZSBhZGQgdGhlIGFnZSB2YWx1ZXMgYW5kIHRoZW4gcmVzaGFwZSB0aGF0IDEwLWJ5LTQgbWF0cml4IGFzIGZvbGxvd3M6DQpgYGB7cn0NCnByb2JzIDwtIGRhdGEuZnJhbWUoYWdlID0gYygxNzoyNiksIHByb2JzKSAlPiUgDQogIGdhdGhlcihrZXkgPSAiTW9kZSIsIHZhbHVlID0gIlByb2JhYmlsaXR5IiwgLWFnZSkNCmBgYA0KDQpCeSAiZ2F0aGVyaW5nIiB0aGUgcHJvYmFiaWxpdGllcywgbm93IHRoZSBkYXRhIGZyYW1lIGhhcyBvbmUgY29sdW1uIHdpdGggdGhlIG1vZGUgYW5kIG9uZSBjb2x1bW4gd2l0aCB0aGUgcHJvYmFiaWxpdHkuIFdlIGNhbiB0aGVuIHBsb3QsIHVzaW5nIGEgZGlmZmVyZW50IGNvbG9ycyBmb3IgZWFjaCBhbHRlcm5hdGl2ZToNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwcm9icywgYWVzKHggPSBhZ2UsIHkgPSBQcm9iYWJpbGl0eSwgY29sb3IgPSBNb2RlKSkgKw0KICBnZW9tX2xpbmUoKQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2Ygd2Fsa2luZyAoZm9yIGEgdHJpcCB0aGF0IHRha2VzIHRoZSBtZWRpYW4gZHVyYXRpb24gaW4gdGhlIHNhbXBsZSkgZGVjbGluZXMgd2l0aCBhZ2UuIFRoZSBwcm9iYWJpbGl0eSBvZiB1c2luZyB0aGUgdGhyZWUgb3RoZXIgbW9kZXMgaW5jcmVhc2VzIHdpdGggYWdlLCBidXQgbW9yZSByYXBpZGx5IGZvciBjYXIgdGhhbiBmb3IgdHJhbnNpdCBvciBjeWNsaW5nLg0KDQojIyBDb21wYXJpbmcgbW9kZWxzOiBNY0ZhZGRlbidzICRccmhvXjIkDQoNClRoZSBsb2ctbGlrZWxpaG9vZCByZXBvcnRlZCBpbiB0aGUgc3VtbWFyeSBvZiB0aGUgbW9kZWwgaXMgdXNlZnVsIGFzIGEgbWVhc3VyZSBvZiBnb29kbmVzcyBvZiBmaXQuIFJlY2FsbCB0aGF0IHRoZSBsaWtlbGlob29kIG9mIHRoaXMgbW9kZWwgaXMgYm91bmRlZCBiZXR3ZWVuICQwJCBhbmQgJDEkLCBhbmQgdGhlcmVmb3JlIHRoZSBsb2ctbGlrZWxpaG9vZCBpcyBib3VuZGVkIGF0IHRoZSB1cHBlciBlbmQgYnkgJDAkIChpdCBpcyBtaW51cyBpbmZpbml0eSBhdCB0aGUgbG93ZXIgZW5kKS4gV2UgYWxzbyBrbm93IHRoYXQgaGlnaGVyIHZhbHVlcyBvZiB0aGUgbGlrZWxpaG9vZCByZXByZXNlbnQgYmV0dGVyIGZpdHMuIA0KDQpPbmUgc2ltcGxlIGRpYWdub3N0aWMgdG8gY29tcGFyZSB0aGUgZml0IG9mIG1vZGVscyBpcyBNY0ZhZGRlbidzICRccmhvXjIkLiBUaGlzIHN1bW1hcnkgZGlhZ25vc3RpYyBpcyBkZWZpbmVkIGFzIGZvbGxvd3M6DQokJA0KXHJob14yID0gMSAtIFxmcmFje2xeKn17bF8wfQ0KJCQNCndoZXJlICRsXiokIGlzIHRoZSB2YWx1ZSBvZiB0aGUgbWF4aW1pemVkIGxvZy1saWtlbGlob29kIGFuZCAkbF8wJCBpcyB0aGUgdmFsdWUgb2YgdGhlIGxvZy1saWtlbGlob29kIG9mIGEgbnVsbCBtb2RlbCAocGVyaGFwcyB3aXRob3V0IGNvbnN0YW50cywgb3IgYSBjb25zdGFudHMgb25seSBtb2RlbCkuIElmIHRoZSBtb2RlbCBpcyB1bmluZm9ybWF0aXZlLCBpdHMgbG9nLWxpa2VsaWhvb2Qgd2lsbCB0ZW5kIHRvIHRoZSBsaWtlbGlob29kIG9mIHRoZSBudWxsIG1vZGVsLiBJbiB0aGlzIGNhc2UgJGxeKi9sXzAkIHRlbmRzIHRvIG9uZSBhbmQgdGhlcmVmb3JlICRccmhvXjIkIHRlbmRzIHRvIHplcm8uIElmIHRoZSBtYXhpbWl6ZWQgbG9nLWxpa2VsaWhvb2Qgb2YgdGhlIG1vZGVsIHRlbmRzIHRvIDAgKHRoZSB1cHBlciBsaW1pdCBmb3IgdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uKSwgJFxyaG9eMiQgdGVuZHMgdG8gb25lLg0KDQpBbHRob3VnaCAkXHJob14yJCBpcyBib3VuZGVkIGJldHdlZW4gemVybyBhbmQgb25lLCBqdXN0IGxpa2UgdGhlIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24gJFJeMiQgaW4gcmVncmVzc2lvbiBhbmFseXNpcywgaXRzIGludGVycHJldGF0aW9uIGlzIF9ub3RfIHRoZSBzYW1lIGFzIGZvciAkUl4yJC4gV2hlcmVhcyAkUl4yJCBpcyBpbnRlcnByZXRlZCBhcyB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlIG1vZGVsLCAkXHJob14yJCBsYWNrcyBzdWNoIGFuIGludGVycHJldGF0aW9uLiBBbHNvLCB0aGUgdmFsdWVzIG9mICRccmhvXjIkIHRlbmQgdG8gYmUgbG93ZXIsIGFuZCB2YWx1ZXMgb2YgJDAuNCQgYXJlIGNvbnZlbnRpb25hbGx5IGNvbnNpZGVyZWQgdmVyeSBnb29kIGZpdHMuIFRoZSBtYWluIHV0aWxpdHkgb2YgTWNGYWRkZW4ncyAkXHJob14yJCBpcyBhcyBhIHF1aWNrIHdheSBvZiBjb21wYXJpbmcgdGhlIHJlbGF0aXZlIGZpdCBvZiBkaWZmZXJlbnQgbW9kZWxzLCByYXRoZXIgdGhhbiBhc3Nlc3NpbmcgdGhlIGZpdCBhZ2FpbnN0IGFuIGFic29sdXRlIHZhbHVlIG9mIGdvb2RuZXNzIG9mIGZpdC4NCg0KIyMgQ29tcGFyaW5nIG1vZGVsczogdGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdA0KDQpBbm90aGVyIHdheSB0byBjb21wYXJlIG1vZGVscyBpcyBieSBtZWFucyBvZiB0aGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0LiBUaGlzIHRlc3QgY29tcGFyZXMgdGhlIGxvZy1saWtlbGlob29kIG9mIHR3byBtb2RlbHMgdG8gYXNzZXNzIHdoZXRoZXIgdGhleSBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQuIFRoZSB0ZXN0IGZvbGxvd3MgdGhlICRcY2hpXjIkIGRpc3RyaWJ1dGlvbiB3aXRoIGRlZ3JlZXMgb2YgZnJlZWRvbSBlcXVhbCB0byB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgbnVtYmVyIG9mIGNvZWZmaWNpZW50cyBiZXR3ZWVuIHRoZSB0d28gbW9kZWxzLiBUaGUgdGVzdCByZXF1aXJlcyBhIGJhc2UgbW9kZWwgYW5kIGEgZnVsbCBtb2RlbCwgYW5kIHRoZSBiYXNlIG1vZGVsIG11c3QgX25lc3RfIHdpdGhpbiB0aGUgZnVsbCBtb2RlbC4gTmVzdGluZyBpbiB0aGlzIHNlbnNlIG1lYW5zIHRoYXQgZnVsbCBtb2RlbCBtdXN0IGJlIHJlZHVjaWJsZSB0byB0aGUgYmFzZSBtb2RlbCBieSBzZXR0aW5nIHNvbWUgY29lZmZpY2llbnRzIHRvIHplcm8uDQoNCkZvciBleGFtcGxlLCBjb25zaWRlciB0aGUgdXRpbGl0eSBmdW5jdGlvbnMgb2YgYG1vZGVsMmA6DQokJA0KXGJlZ2lue2FycmF5fXtsfQ0KICBWX3tpXHRleHR7Q3ljbGV9fSA9IDAgJismIFxiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0N5Y2xlfX0gJismIDBcXA0KICBWX3tpXHRleHR7V2Fsa319ID0gXG11X3tcdGV4dHtXYWxrfX0gJismIFxiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e1dhbGt9fSAmKyYgXGdhbW1hX3sxfVx0ZXh0e2FnZX1fe2l9XFwNCiAgVl97aVx0ZXh0e0hTUn19ID0gXG11X3tcdGV4dHtIU1J9fSAmKyYgXGJldGFfMVx0ZXh0e3RpbWV9X3tpXHRleHR7SFNSfX0gJismIFxnYW1tYV97Mn1cdGV4dHthZ2V9X3tpfVxcDQogIFZfe2lcdGV4dHtIU1J9fSA9IFxtdV97XHRleHR7Q2FyfX0gJismIFxiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0Nhcn19ICYrJiBcZ2FtbWFfezN9XHRleHR7YWdlfV97aX1cXA0KXGVuZHthcnJheX0gIA0KJCQNCg0KV2UgY2FuIHJlZHVjZSB0aGlzIG1vZGVsIHRvIGBtb2RlbDFgIGJ5IHNldHRpbmcgJFxnYW1tYV97MX09XGdhbW1hX3syfT1cZ2FtbWFfezN9PTAkOg0KJCQNClxiZWdpbnthcnJheX17bH0NCiAgVl97aVx0ZXh0e0N5Y2xlfX0gPSAwICYrJiBcYmV0YV8xXHRleHR7dGltZX1fe2lcdGV4dHtDeWNsZX19XFwNCiAgVl97aVx0ZXh0e1dhbGt9fSA9IFxtdV97XHRleHR7V2Fsa319ICYrJiBcYmV0YV8xXHRleHR7dGltZX1fe2lcdGV4dHtXYWxrfX1cXA0KICBWX3tpXHRleHR7SFNSfX0gPSBcbXVfe1x0ZXh0e0hTUn19ICYrJiBcYmV0YV8xXHRleHR7dGltZX1fe2lcdGV4dHtIU1J9fVxcDQogIFZfe2lcdGV4dHtIU1J9fSA9IFxtdV97XHRleHR7Q2FyfX0gJismIFxiZXRhXzFcdGV4dHt0aW1lfV97aVx0ZXh0e0Nhcn19XFwNClxlbmR7YXJyYXl9ICANCiQkDQoNCkluIHRoaXMgd2F5LCBgbW9kZWwxYCAibmVzdHMiIGluIGBtb2RlbDJgLg0KDQpJbiB0aGUgc3VtbWFyeSBvZiB0aGUgbW9kZWxzLCB0aGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0IGlzIHJlcG9ydGVkLiBTZWU6DQpgYGB7cn0NCnN1bW1hcnkobW9kZWwxKQ0KYGBgDQoNClRoZSB0ZXN0IHJlcG9ydGVkIGluIHRoZSBvdXRwdXQgb2YgdGhlIG1vZGVsIGlzIGFnYWluc3QgdGhlIG51bGwgbW9kZWwsIHRoYXQgaXMsIGEgbW9kZWwgd2l0aCBubyB2YXJpYWJsZXMgYXQgYWxsLiBUaGlzIGlzIHRoZSBsZWFzdCBpbmZvcm1hdGl2ZSBvZiBhbGwgbW9kZWxzLg0KDQpXaGVuIHR3byBub24tbnVsbCBtb2RlbHMgbmVlZCB0byBiZSBjb21wYXJlZCwgdGhlIGBscnRlc3RgIGZ1bmN0aW9uIGltcGxlbWVudHMgdGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBmb3IgdHdvIGlucHV0cywgd2hpY2ggYXJlIHR3byBgbWxvZ2l0YCBtb2RlbHMsIGFzIGZvbGxvd3M6DQpgYGB7cn0NCmxydGVzdChtb2RlbDEsIG1vZGVsMikNCmBgYA0KDQpOb3RpY2UgdGhhdCB0aGUgbnVtYmVyIG9mIGRlZ3JlZXMgb2YgZnJlZWRvbSAoRGYpIGlzICQzJDogdGhpcyBpcyBiZWNhdXNlIHRoZXJlIGFyZSB0aHJlZSBpbmRpdmlkdWFsLXNwZWNpZmljIHBhcmFtZXRlcnMgaW4gYG1vZGVsMmAgdGhhdCBhcmUgbm90IHByZXNlbnQgaW4gYG1vZGVsMWAuIFRoZSBudWxsIGh5cG90aGVzaXMgb2YgdGhlIHRlc3QgaXMgdGhhdCB0aGUgbG9nLWxpa2VsaWhvb2Qgb2YgdGhlIHR3byBtb2RlbHMgaXMgbm90IGRpZmZlcmVudCwgaW4gb3RoZXIgd29yZHMsIHRoYXQgdGhlIGFsdGVybmF0ZSBtb2RlbCBpcyBub3QgYW4gaW1wcm92ZW1lbnQgb3ZlciB0aGUgYmFzZSBtb2RlbC4NCg0KSW4gdGhlIHByZXNlbnQgY2FzZSwgdGhlIHZlcnkgc21hbGwgJHAkLXZhbHVlIGxlYWRzIHVzIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLCBhbmQgdGhlIGNvbmNsdXNpb24gaXMgdGhhdCBgbW9kZWwyYCwgd2hpY2ggaW5jbHVkZXMgYWdlLCBpcyBhIHNpZ25pZmljYW50IGltcHJvdmVtZW50IG92ZXIgYG1vZGVsMWAsIHdoaWNoIGRvZXMgbm90Lg0KDQojIyBFeGVyY2lzZQ0KDQoxLiBJbiB0aGUgZXhhbXBsZSBpbiB0aGlzIGNoYXB0ZXIgd2UgZXN0aW1hdGVkIHRoZSBwcm9iYWJpbGl0aWVzIG9mIGNob29zaW5nIGRpZmZlcmVudCBtb2RlcyBieSBhZ2Ugc2V0dGluZyB0cmF2ZWwgdGltZSB0byB0aGUgaW4tc2FtcGxlIG1lZGlhbi4gVXNlIGBtb2RlbDJgIHRvIGNhbGN1bGF0ZSB0aGUgcHJvYmFiaWxpdHkgb2YgY2hvb3NpbmcgdGhlIG1vZGVzIGJ1dCBub3cgYXMgYSBmdW5jdGlvbiBvZiAqKnRyYXZlbCB0aW1lKiosIGZvciBhZ2VzIDE3LCAyMCwgMjMsIGFuZCAyNi4NCg0KMi4gRXN0aW1hdGUgYSBtb2RlbCB1c2luZyBmb3JtdWxhIGBmM2AgKGNhbGwgaXQgYG1vZGVsM2ApLiBEaXNjdXNzIHRoZSBvdXRwdXQgb2YgdGhpcyBtb2RlbC4NCg0KMy4gVXNlIHRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3QgdG8gY29tcGFyZSBgbW9kZWwzYCB0byBgbW9kZWwxYC4NCg0KNC4gQ2FuIHlvdSB1c2UgdGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCB0byBjb21wYXJlIGBtb2RlbDNgIHRvIGBtb2RlbDJgPyBEaXNjdXNzLg==